about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/bootstrap.md70
-rw-r--r--.gitignore1
-rw-r--r--CONTRIBUTING.md9
-rw-r--r--Cargo.lock250
-rw-r--r--RELEASES.md2
-rw-r--r--compiler/rustc_ast/src/entry.rs10
-rw-r--r--compiler/rustc_ast_lowering/src/delegation.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/index.rs41
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs1
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs24
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs14
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/repr.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs9
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs4
-rw-r--r--compiler/rustc_borrowck/src/lib.rs10
-rw-r--r--compiler/rustc_borrowck/src/places_conflict.rs3
-rw-r--r--compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs9
-rw-r--r--compiler/rustc_borrowck/src/type_check/canonical.rs4
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/source_util.rs11
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs7
-rw-r--r--compiler/rustc_codegen_cranelift/rust-toolchain2
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh5
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs10
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/src/main_shim.rs21
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/test.rs26
-rw-r--r--compiler/rustc_codegen_gcc/example/alloc_example.rs7
-rw-r--r--compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs2
-rw-r--r--compiler/rustc_codegen_gcc/example/mod_bench.rs36
-rw-r--r--compiler/rustc_codegen_gcc/src/common.rs5
-rw-r--r--compiler/rustc_codegen_gcc/src/context.rs1
-rw-r--r--compiler/rustc_codegen_gcc/src/debuginfo.rs18
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/abort1.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/abort2.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/array.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/assign.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/closure.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/condition.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/empty_main.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/exit.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/exit_code.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/mut_ref.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/operations.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/return-tuple.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/slice.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/static.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/structs.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/tuple.rs7
-rw-r--r--compiler/rustc_codegen_llvm/Cargo.toml2
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs9
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs59
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs21
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml2
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl2
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs11
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs59
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs102
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs21
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/consts.rs1
-rw-r--r--compiler/rustc_const_eval/messages.ftl2
-rw-r--r--compiler/rustc_const_eval/src/check_consts/check.rs38
-rw-r--r--compiler/rustc_const_eval/src/check_consts/ops.rs18
-rw-r--r--compiler/rustc_const_eval/src/check_consts/qualifs.rs4
-rw-r--r--compiler/rustc_const_eval/src/check_consts/resolver.rs1
-rw-r--r--compiler/rustc_const_eval/src/errors.rs9
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs21
-rw-r--r--compiler/rustc_data_structures/Cargo.toml2
-rw-r--r--compiler/rustc_data_structures/src/flock/windows.rs4
-rw-r--r--compiler/rustc_driver_impl/Cargo.toml2
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs163
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0038.md6
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0132.md33
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0138.md26
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0647.md14
-rw-r--r--compiler/rustc_error_codes/src/lib.rs4
-rw-r--r--compiler/rustc_errors/Cargo.toml2
-rw-r--r--compiler/rustc_errors/src/emitter.rs2
-rw-r--r--compiler/rustc_errors/src/json.rs3
-rw-r--r--compiler/rustc_errors/src/lib.rs3
-rw-r--r--compiler/rustc_expand/src/config.rs2
-rw-r--r--compiler/rustc_expand/src/mbe/diagnostics.rs2
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs20
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs1
-rw-r--r--compiler/rustc_feature/src/removed.rs7
-rw-r--r--compiler/rustc_feature/src/unstable.rs13
-rw-r--r--compiler/rustc_hir/src/def.rs2
-rw-r--r--compiler/rustc_hir/src/lang_items.rs4
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl15
-rw-r--r--compiler/rustc_hir_analysis/src/autoderef.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/check/entry.rs83
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/mod.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs42
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs203
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs50
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs16
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs9
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs76
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs9
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs11
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs25
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs211
-rw-r--r--compiler/rustc_index/src/interval.rs2
-rw-r--r--compiler/rustc_infer/src/infer/context.rs2
-rw-r--r--compiler/rustc_infer/src/infer/relate/higher_ranked.rs6
-rw-r--r--compiler/rustc_infer/src/traits/util.rs6
-rw-r--r--compiler/rustc_interface/src/interface.rs33
-rw-r--r--compiler/rustc_interface/src/passes.rs22
-rw-r--r--compiler/rustc_interface/src/tests.rs9
-rw-r--r--compiler/rustc_lint/messages.ftl6
-rw-r--r--compiler/rustc_lint/src/expect.rs2
-rw-r--r--compiler/rustc_lint/src/if_let_rescope.rs11
-rw-r--r--compiler/rustc_lint/src/lints.rs8
-rw-r--r--compiler/rustc_lint/src/types.rs134
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp182
-rw-r--r--compiler/rustc_metadata/src/creader.rs3
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs5
-rw-r--r--compiler/rustc_middle/src/mir/consts.rs3
-rw-r--r--compiler/rustc_middle/src/mir/coverage.rs8
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs4
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs1
-rw-r--r--compiler/rustc_middle/src/mir/statement.rs1
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs10
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs1
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs8
-rw-r--r--compiler/rustc_middle/src/query/arena_cached.rs47
-rw-r--r--compiler/rustc_middle/src/query/mod.rs9
-rw-r--r--compiler/rustc_middle/src/query/plumbing.rs20
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs3
-rw-r--r--compiler/rustc_middle/src/ty/closure.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs14
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs2
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs3
-rw-r--r--compiler/rustc_middle/src/ty/predicate.rs10
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs4
-rw-r--r--compiler/rustc_middle/src/ty/vtable.rs3
-rw-r--r--compiler/rustc_middle/src/values.rs2
-rw-r--r--compiler/rustc_mir_build/messages.ftl12
-rw-r--r--compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs1
-rw-r--r--compiler/rustc_mir_build/src/builder/expr/as_place.rs110
-rw-r--r--compiler/rustc_mir_build/src/builder/matches/mod.rs11
-rw-r--r--compiler/rustc_mir_build/src/builder/matches/test.rs7
-rw-r--r--compiler/rustc_mir_build/src/builder/mod.rs7
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs2
-rw-r--r--compiler/rustc_mir_build/src/errors.rs22
-rw-r--r--compiler/rustc_mir_build/src/lib.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs15
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/graphviz.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs1
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs1
-rw-r--r--compiler/rustc_mir_transform/messages.ftl12
-rw-r--r--compiler/rustc_mir_transform/src/check_call_recursion.rs (renamed from compiler/rustc_mir_build/src/lints.rs)81
-rw-r--r--compiler/rustc_mir_transform/src/check_inline.rs (renamed from compiler/rustc_mir_build/src/check_inline.rs)52
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters.rs310
-rw-r--r--compiler/rustc_mir_transform/src/coverage/graph.rs2
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs15
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs12
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs1
-rw-r--r--compiler/rustc_mir_transform/src/errors.rs22
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs51
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs6
-rw-r--r--compiler/rustc_mir_transform/src/instsimplify.rs13
-rw-r--r--compiler/rustc_mir_transform/src/known_panics_lint.rs15
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs10
-rw-r--r--compiler/rustc_mir_transform/src/promote_consts.rs4
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs16
-rw-r--r--compiler/rustc_next_trait_solver/Cargo.toml1
-rw-r--r--compiler/rustc_next_trait_solver/src/canonicalizer.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/mod.rs42
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs48
-rw-r--r--compiler/rustc_parse/src/lib.rs67
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs2
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs8
-rw-r--r--compiler/rustc_parse_format/src/lib.rs10
-rw-r--r--compiler/rustc_passes/messages.ftl5
-rw-r--r--compiler/rustc_passes/src/check_attr.rs2
-rw-r--r--compiler/rustc_passes/src/dead.rs2
-rw-r--r--compiler/rustc_passes/src/entry.rs27
-rw-r--r--compiler/rustc_passes/src/errors.rs11
-rw-r--r--compiler/rustc_privacy/messages.ftl18
-rw-r--r--compiler/rustc_privacy/src/errors.rs14
-rw-r--r--compiler/rustc_privacy/src/lib.rs151
-rw-r--r--compiler/rustc_query_system/src/query/job.rs6
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs54
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs2
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs511
-rw-r--r--compiler/rustc_resolve/src/effective_visibilities.rs59
-rw-r--r--compiler/rustc_resolve/src/ident.rs98
-rw-r--r--compiler/rustc_resolve/src/imports.rs261
-rw-r--r--compiler/rustc_resolve/src/late.rs230
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs6
-rw-r--r--compiler/rustc_resolve/src/lib.rs2
-rw-r--r--compiler/rustc_resolve/src/macros.rs53
-rw-r--r--compiler/rustc_resolve/src/rustdoc.rs5
-rw-r--r--compiler/rustc_session/Cargo.toml2
-rw-r--r--compiler/rustc_session/src/config.rs15
-rw-r--r--compiler/rustc_session/src/filesearch.rs2
-rw-r--r--compiler/rustc_session/src/session.rs4
-rw-r--r--compiler/rustc_smir/src/rustc_internal/mod.rs4
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mir.rs1
-rw-r--r--compiler/rustc_span/src/hygiene.rs4
-rw-r--r--compiler/rustc_span/src/lib.rs55
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_target/src/callconv/powerpc64.rs4
-rw-r--r--compiler/rustc_target/src/spec/base/windows_gnu.rs2
-rw-r--r--compiler/rustc_target/src/spec/base/windows_gnullvm.rs2
-rw-r--r--compiler/rustc_trait_selection/messages.ftl3
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs6
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs12
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs24
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs164
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs188
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs14
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs30
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs7
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs23
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs15
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_normalize.rs73
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs209
-rw-r--r--compiler/rustc_type_ir/src/visit.rs8
-rw-r--r--library/Cargo.lock4
-rw-r--r--library/alloc/src/bstr.rs702
-rw-r--r--library/alloc/src/collections/btree/set.rs8
-rw-r--r--library/alloc/src/lib.rs4
-rw-r--r--library/core/src/arch.rs10
-rw-r--r--library/core/src/array/mod.rs3
-rw-r--r--library/core/src/bstr.rs581
-rw-r--r--library/core/src/cell.rs4
-rw-r--r--library/core/src/clone.rs10
-rw-r--r--library/core/src/escape.rs22
-rw-r--r--library/core/src/ffi/mod.rs20
-rw-r--r--library/core/src/hint.rs135
-rw-r--r--library/core/src/intrinsics/mir.rs3
-rw-r--r--library/core/src/lib.rs8
-rw-r--r--library/core/src/net/display_buffer.rs6
-rw-r--r--library/core/src/net/ip_addr.rs11
-rw-r--r--library/core/src/num/dec2flt/decimal.rs20
-rw-r--r--library/core/src/num/dec2flt/fpu.rs8
-rw-r--r--library/core/src/num/dec2flt/table.rs9
-rw-r--r--library/core/src/num/int_log10.rs28
-rw-r--r--library/core/src/num/int_sqrt.rs8
-rw-r--r--library/core/src/num/overflow_panic.rs16
-rw-r--r--library/core/src/num/uint_macros.rs33
-rw-r--r--library/core/src/num/wrapping.rs38
-rw-r--r--library/core/src/ops/index_range.rs14
-rw-r--r--library/core/src/ops/try_trait.rs7
-rw-r--r--library/core/src/slice/mod.rs91
-rw-r--r--library/core/src/slice/rotate.rs2
-rw-r--r--library/core/src/unicode/mod.rs2
-rw-r--r--library/core/tests/bstr.rs54
-rw-r--r--library/core/tests/net/ip_addr.rs10
-rw-r--r--library/panic_unwind/src/dummy.rs4
-rw-r--r--library/panic_unwind/src/emcc.rs4
-rw-r--r--library/panic_unwind/src/gcc.rs4
-rw-r--r--library/panic_unwind/src/hermit.rs4
-rw-r--r--library/panic_unwind/src/lib.rs1
-rw-r--r--library/panic_unwind/src/miri.rs4
-rw-r--r--library/panic_unwind/src/seh.rs32
-rw-r--r--library/rtstartup/rsbegin.rs1
-rw-r--r--library/rtstartup/rsend.rs1
-rw-r--r--library/std/src/bstr.rs4
-rw-r--r--library/std/src/env.rs8
-rw-r--r--library/std/src/ffi/os_str.rs4
-rw-r--r--library/std/src/keyword_docs.rs9
-rw-r--r--library/std/src/lib.rs4
-rw-r--r--library/std/src/os/fd/raw.rs5
-rw-r--r--library/std/src/os/wasi/io/fd.rs9
-rw-r--r--library/std/src/os/wasi/io/mod.rs4
-rw-r--r--library/std/src/os/wasi/io/raw.rs20
-rw-r--r--library/std/src/os/wasi/io/tests.rs (renamed from library/std/src/os/wasi/io/fd/tests.rs)0
-rw-r--r--library/std/src/rt.rs5
-rw-r--r--library/std/src/sys/pal/windows/fs.rs3
-rw-r--r--library/std/src/thread/local.rs24
-rw-r--r--src/bootstrap/Cargo.lock25
-rw-r--r--src/bootstrap/Cargo.toml2
-rw-r--r--src/bootstrap/bootstrap.py5
-rw-r--r--src/bootstrap/defaults/config.compiler.toml2
-rw-r--r--src/bootstrap/mk/Makefile.in13
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs13
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs96
-rw-r--r--src/bootstrap/src/core/builder/cargo.rs4
-rw-r--r--src/bootstrap/src/core/config/config.rs42
-rw-r--r--src/bootstrap/src/core/config/tests.rs2
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/ci/docker/README.md8
-rw-r--r--src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile1
-rw-r--r--src/ci/docker/host-x86_64/dist-mips-linux/mips-linux-gnu.defconfig2
-rw-r--r--src/ci/docker/host-x86_64/dist-mips-linux/patches/glibc/2.23/0001-MIPS-SPARC-fix-wrong-vfork-aliases-in-libpthread.so.patch44
-rw-r--r--src/ci/docker/host-x86_64/dist-mips-linux/patches/glibc/2.23/0002-MIPS-SPARC-more-fixes-to-the-vfork-aliases-in-libpth.patch63
-rw-r--r--src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile1
-rw-r--r--src/ci/docker/host-x86_64/dist-mips64-linux/mips64-linux-gnu.defconfig2
-rw-r--r--src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile1
-rw-r--r--src/ci/docker/host-x86_64/dist-mips64el-linux/mips64el-linux-gnu.defconfig2
-rw-r--r--src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile1
-rw-r--r--src/ci/docker/host-x86_64/dist-mipsel-linux/mipsel-linux-gnu.defconfig2
-rw-r--r--src/ci/docker/host-x86_64/dist-various-2/Dockerfile6
-rw-r--r--src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile6
-rw-r--r--src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile4
-rwxr-xr-xsrc/ci/docker/run.sh9
-rwxr-xr-xsrc/ci/docker/scripts/freebsd-toolchain.sh6
-rw-r--r--src/ci/github-actions/jobs.yml31
-rw-r--r--src/doc/rustc-dev-guide/examples/rustc-driver-example.rs15
-rw-r--r--src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs15
-rw-r--r--src/doc/rustc-dev-guide/src/rustc-driver/intro.md4
-rw-r--r--src/doc/rustc-dev-guide/src/stability.md3
-rw-r--r--src/doc/rustc-dev-guide/src/tests/directives.md5
-rw-r--r--src/doc/rustc/src/platform-support/nto-qnx.md2
-rw-r--r--src/doc/unstable-book/src/language-features/lang-items.md9
-rw-r--r--src/doc/unstable-book/src/language-features/start.md59
-rwxr-xr-xsrc/etc/dec2flt_table.py10
-rw-r--r--src/librustdoc/clean/cfg.rs117
-rw-r--r--src/librustdoc/core.rs7
-rw-r--r--src/librustdoc/doctest.rs2
-rw-r--r--src/librustdoc/html/format.rs90
-rw-r--r--src/librustdoc/html/highlight.rs10
-rw-r--r--src/librustdoc/html/highlight/tests.rs2
-rw-r--r--src/librustdoc/html/render/mod.rs31
-rw-r--r--src/librustdoc/html/render/print_item.rs82
-rw-r--r--src/librustdoc/html/render/sidebar.rs5
-rw-r--r--src/librustdoc/html/render/type_layout.rs3
-rw-r--r--src/librustdoc/html/sources.rs14
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css48
-rw-r--r--src/librustdoc/lib.rs18
-rw-r--r--src/rustdoc-json-types/lib.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs3
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs2
-rw-r--r--src/tools/clippy/src/driver.rs12
-rw-r--r--src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed13
-rw-r--r--src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs13
-rw-r--r--src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr4
-rw-r--r--src/tools/clippy/tests/ui/box_default_no_std.rs13
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-7410.rs13
-rw-r--r--src/tools/clippy/tests/ui/crate_level_checks/no_std_main_recursion.rs32
-rw-r--r--src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.fixed3
-rw-r--r--src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs3
-rw-r--r--src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr2
-rw-r--r--src/tools/clippy/tests/ui/def_id_nocore.rs2
-rw-r--r--src/tools/clippy/tests/ui/empty_loop_no_std.rs20
-rw-r--r--src/tools/clippy/tests/ui/empty_loop_no_std.stderr12
-rw-r--r--src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs13
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs10
-rw-r--r--src/tools/clippy/tests/ui/missing_spin_loop_no_std.fixed13
-rw-r--r--src/tools/clippy/tests/ui/missing_spin_loop_no_std.rs13
-rw-r--r--src/tools/clippy/tests/ui/missing_spin_loop_no_std.stderr2
-rw-r--r--src/tools/clippy/tests/ui/result_unit_error_no_std.rs7
-rw-r--r--src/tools/clippy/tests/ui/result_unit_error_no_std.stderr2
-rw-r--r--src/tools/clippy/tests/ui/zero_ptr_no_std.fixed13
-rw-r--r--src/tools/clippy/tests/ui/zero_ptr_no_std.rs13
-rw-r--r--src/tools/clippy/tests/ui/zero_ptr_no_std.stderr6
-rw-r--r--src/tools/compiletest/Cargo.toml2
-rw-r--r--src/tools/compiletest/src/directive-list.rs1
-rw-r--r--src/tools/compiletest/src/errors.rs2
-rw-r--r--src/tools/compiletest/src/header/cfg.rs6
-rw-r--r--src/tools/compiletest/src/runtest.rs3
-rw-r--r--src/tools/linkchecker/main.rs23
-rw-r--r--src/tools/miri/.github/workflows/ci.yml2
-rw-r--r--src/tools/miri/CONTRIBUTING.md2
-rw-r--r--src/tools/miri/README.md4
-rwxr-xr-xsrc/tools/miri/ci/ci.sh5
-rw-r--r--src/tools/miri/etc/rust_analyzer_vscode.json10
-rwxr-xr-xsrc/tools/miri/miri10
-rw-r--r--src/tools/miri/miri-script/src/commands.rs6
-rw-r--r--src/tools/miri/miri-script/src/main.rs1
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/bin/miri.rs37
-rw-r--r--src/tools/miri/src/concurrency/cpu_affinity.rs8
-rw-r--r--src/tools/miri/src/concurrency/sync.rs90
-rw-r--r--src/tools/miri/src/concurrency/thread.rs83
-rw-r--r--src/tools/miri/src/eval.rs20
-rw-r--r--src/tools/miri/src/helpers.rs8
-rw-r--r--src/tools/miri/src/lib.rs14
-rw-r--r--src/tools/miri/src/machine.rs66
-rw-r--r--src/tools/miri/src/shims/files.rs259
-rw-r--r--src/tools/miri/src/shims/native_lib.rs2
-rw-r--r--src/tools/miri/src/shims/time.rs12
-rw-r--r--src/tools/miri/src/shims/unix/fd.rs9
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs323
-rw-r--r--src/tools/miri/src/shims/unix/freebsd/foreign_items.rs27
-rw-r--r--src/tools/miri/src/shims/unix/fs.rs36
-rw-r--r--src/tools/miri/src/shims/unix/linux_like/epoll.rs181
-rw-r--r--src/tools/miri/src/shims/unix/linux_like/eventfd.rs99
-rw-r--r--src/tools/miri/src/shims/unix/macos/foreign_items.rs32
-rw-r--r--src/tools/miri/src/shims/unix/macos/sync.rs2
-rw-r--r--src/tools/miri/src/shims/unix/solarish/foreign_items.rs36
-rw-r--r--src/tools/miri/src/shims/unix/unnamed_socket.rs218
-rw-r--r--src/tools/miri/src/shims/windows/handle.rs2
-rw-r--r--src/tools/miri/src/shims/windows/sync.rs3
-rw-r--r--src/tools/miri/test-cargo-miri/no-std-smoke/src/main.rs5
-rw-r--r--src/tools/miri/tests/fail-dep/libc/affinity.rs3
-rw-r--r--src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/libc_epoll_unsupported_fd.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/memrchr_null.rs5
-rw-r--r--src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs37
-rw-r--r--src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr35
-rw-r--r--src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.rs7
-rw-r--r--src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr2
-rw-r--r--src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.rs7
-rw-r--r--src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr2
-rw-r--r--src/tools/miri/tests/fail/alloc/no_global_allocator.rs6
-rw-r--r--src/tools/miri/tests/fail/alloc/no_global_allocator.stderr2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/cttz_nonzero.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.rs5
-rw-r--r--src/tools/miri/tests/fail/panic/no_std.rs7
-rw-r--r--src/tools/miri/tests/fail/panic/no_std.stderr2
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-affinity.rs3
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs2
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs2
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs7
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-fs.rs20
-rw-r--r--src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs54
-rw-r--r--src/tools/miri/tests/pass/alloc-access-tracking.rs6
-rw-r--r--src/tools/miri/tests/pass/alloc-access-tracking.stderr8
-rw-r--r--src/tools/miri/tests/pass/intrinsics/portable-simd.rs7
-rw-r--r--src/tools/miri/tests/pass/miri-alloc.rs6
-rw-r--r--src/tools/miri/tests/pass/miri_start.stdout1
-rw-r--r--src/tools/miri/tests/pass/no_std.rs19
-rw-r--r--src/tools/miri/tests/pass/no_std_miri_start.rs (renamed from src/tools/miri/tests/pass/miri_start.rs)4
-rw-r--r--src/tools/miri/tests/pass/no_std_miri_start.stdout (renamed from src/tools/miri/tests/pass/no_std.stdout)0
-rw-r--r--src/tools/miri/tests/pass/shims/pipe.rs13
-rw-r--r--src/tools/miri/tests/pass/start.rs8
-rw-r--r--src/tools/miri/tests/pass/start.stdout1
-rw-r--r--src/tools/miri/triagebot.toml8
-rw-r--r--src/tools/opt-dist/src/tests.rs9
-rw-r--r--src/tools/run-make-support/src/command.rs55
-rw-r--r--src/tools/run-make-support/src/macros.rs11
-rw-r--r--src/tools/rust-analyzer/Cargo.lock102
-rw-r--r--src/tools/rust-analyzer/Cargo.toml24
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/edition/src/lib.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs44
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs23
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expander.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/find_path.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/import_map.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs30
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs60
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/visibility.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs105
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/db.rs37
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/files.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs46
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/lib.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs21
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/name.rs49
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs49
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs33
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests.rs23
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/variance.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/attrs.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/display.rs33
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs118
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs66
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs32
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs74
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/symbols.rs253
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs36
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs18
-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_macro.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs98
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs27
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs177
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs119
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests.rs45
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/utils.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs32
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/utils/ref_field_expr.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs298
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs57
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs26
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs15
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs41
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs11
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.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.rs46
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/lib.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render.rs140
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests.rs55
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs51
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs202
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs41
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs53
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs93
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs25
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/proc_macros.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs24
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs99
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/defs.rs39
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/documentation.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs43
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs34
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/lib.rs32
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/rename.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/search.rs11
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs53
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt87
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/traits.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs32
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs34
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs31
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs55
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/tests/overly_long_real_world_cases.rs2726
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/annotations.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/expand_macro.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/file_structure.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/fixture.rs20
-rwxr-xr-xsrc/tools/rust-analyzer/crates/ide/src/folding_ranges.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_definition.rs168
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/highlight_related.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover.rs51
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/render.rs78
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs193
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs159
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs24
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs95
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs56
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs152
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs15
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs52
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs26
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/join_lines.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/lib.rs26
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/moniker.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/move_item.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/navigation_target.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/parent_module.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/references.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/rename.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/runnables.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/signature_help.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/ssr.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/static_index.rs11
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html16
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html16
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html16
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html16
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html20
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html110
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html12
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs338
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/typing.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_syntax_tree.rs226
-rw-r--r--src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs5
-rw-r--r--src/tools/rust-analyzer/crates/load-cargo/src/lib.rs5
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs10
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/lib.rs3
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/tests.rs177
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/event.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs23
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/parser.rs25
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0056_let_else_right_curly_brace_struct.rast79
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0056_let_else_right_curly_brace_struct.rs8
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_arithmetic.rast42
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_arithmetic.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_format_args.rast90
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_format_args.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0058_let_else_right_curly_brace_range.rast40
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0058_let_else_right_curly_brace_range.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0059_let_else_right_curly_brace_closure.rast55
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0059_let_else_right_curly_brace_closure.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0060_let_else_right_curly_brace_unary.rast38
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0060_let_else_right_curly_brace_unary.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0061_let_else_right_curly_brace_do_yeet.rast90
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0061_let_else_right_curly_brace_do_yeet.rs7
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0062_let_else_right_curly_brace_become.rast40
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0062_let_else_right_curly_brace_become.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0063_let_else_right_curly_brace_reference.rast38
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0063_let_else_right_curly_brace_reference.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0064_let_else_right_curly_brace_assignment.rast45
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0064_let_else_right_curly_brace_assignment.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rast19
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rs1
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs20
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs11
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs4
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs130
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs13
-rw-r--r--src/tools/rust-analyzer/crates/profile/Cargo.toml5
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/tests.rs3
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs45
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml5
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs45
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs27
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs12
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs11
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs25
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs6
-rw-r--r--src/tools/rust-analyzer/crates/span/src/hygiene.rs29
-rw-r--r--src/tools/rust-analyzer/crates/span/src/map.rs2
-rw-r--r--src/tools/rust-analyzer/crates/stdx/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs17
-rw-r--r--src/tools/rust-analyzer/crates/syntax-bridge/src/to_parser_input.rs44
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs4
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs23
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/make.rs51
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs8
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs364
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs7
-rw-r--r--src/tools/rust-analyzer/crates/test-fixture/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/test-fixture/src/lib.rs96
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/fixture.rs2
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/minicore.rs58
-rw-r--r--src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/docs/dev/README.md16
-rw-r--r--src/tools/rust-analyzer/docs/dev/lsp-extensions.md19
-rw-r--r--src/tools/rust-analyzer/docs/user/generated_config.adoc32
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json147
-rw-r--r--src/tools/rust-analyzer/editors/code/src/ast_inspector.ts216
-rw-r--r--src/tools/rust-analyzer/editors/code/src/commands.ts167
-rw-r--r--src/tools/rust-analyzer/editors/code/src/config.ts4
-rw-r--r--src/tools/rust-analyzer/editors/code/src/ctx.ts93
-rw-r--r--src/tools/rust-analyzer/editors/code/src/lsp_ext.ts4
-rw-r--r--src/tools/rust-analyzer/editors/code/src/main.ts5
-rw-r--r--src/tools/rust-analyzer/editors/code/src/syntax_tree_provider.ts301
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/src/msg.rs8
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/src/socket.rs23
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/src/stdio.rs23
-rw-r--r--src/tools/rust-analyzer/rust-version2
-rw-r--r--src/tools/rustbook/Cargo.lock65
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt2
-rw-r--r--src/tools/tidy/src/deps.rs1
-rw-r--r--src/tools/tidy/src/issues.txt5
-rw-r--r--src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs2
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--src/tools/wasm-component-ld/Cargo.toml2
-rw-r--r--tests/codegen-units/item-collection/cross-crate-closures.rs8
-rw-r--r--tests/codegen-units/item-collection/cross-crate-generic-functions.rs6
-rw-r--r--tests/codegen-units/item-collection/cross-crate-trait-method.rs6
-rw-r--r--tests/codegen-units/item-collection/drop_in_place_intrinsic.rs6
-rw-r--r--tests/codegen-units/item-collection/function-as-argument.rs6
-rw-r--r--tests/codegen-units/item-collection/generic-drop-glue.rs6
-rw-r--r--tests/codegen-units/item-collection/generic-functions.rs6
-rw-r--r--tests/codegen-units/item-collection/generic-impl.rs6
-rw-r--r--tests/codegen-units/item-collection/impl-in-non-instantiated-generic.rs6
-rw-r--r--tests/codegen-units/item-collection/instantiation-through-vtable.rs6
-rw-r--r--tests/codegen-units/item-collection/items-within-generic-items.rs6
-rw-r--r--tests/codegen-units/item-collection/non-generic-closures.rs8
-rw-r--r--tests/codegen-units/item-collection/non-generic-drop-glue.rs6
-rw-r--r--tests/codegen-units/item-collection/non-generic-functions.rs6
-rw-r--r--tests/codegen-units/item-collection/static-init.rs10
-rw-r--r--tests/codegen-units/item-collection/statics-and-consts.rs6
-rw-r--r--tests/codegen-units/item-collection/trait-implementations.rs6
-rw-r--r--tests/codegen-units/item-collection/trait-method-as-argument.rs6
-rw-r--r--tests/codegen-units/item-collection/trait-method-default-impl.rs6
-rw-r--r--tests/codegen-units/item-collection/transitive-drop-glue.rs6
-rw-r--r--tests/codegen-units/item-collection/tuple-drop-glue.rs6
-rw-r--r--tests/codegen-units/item-collection/unsizing.rs6
-rw-r--r--tests/codegen-units/partitioning/methods-are-with-self-type.rs1
-rw-r--r--tests/codegen-units/partitioning/vtable-through-const.rs18
-rw-r--r--tests/codegen/gdb_debug_script_load.rs28
-rw-r--r--tests/codegen/hint/cold_path.rs54
-rw-r--r--tests/codegen/hint/likely.rs81
-rw-r--r--tests/codegen/hint/unlikely.rs80
-rw-r--r--tests/codegen/intrinsics/transmute-niched.rs122
-rw-r--r--tests/codegen/mainsubprogramstart.rs14
-rw-r--r--tests/codegen/overaligned-constant.rs2
-rw-r--r--tests/codegen/slice-init.rs55
-rw-r--r--tests/codegen/transmute-optimized.rs8
-rw-r--r--tests/crashes/130779.rs11
-rw-r--r--tests/crashes/133063.rs8
-rw-r--r--tests/crashes/133117.rs8
-rw-r--r--tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir8
-rw-r--r--tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir8
-rw-r--r--tests/mir-opt/building/custom/arrays.arrays.built.after.mir14
-rw-r--r--tests/mir-opt/building/custom/arrays.rs22
-rw-r--r--tests/mir-opt/building/index_array_and_slice.index_array.built.after.mir31
-rw-r--r--tests/mir-opt/building/index_array_and_slice.index_const_generic_array.built.after.mir31
-rw-r--r--tests/mir-opt/building/index_array_and_slice.index_custom.built.after.mir34
-rw-r--r--tests/mir-opt/building/index_array_and_slice.index_mut_slice.built.after.mir34
-rw-r--r--tests/mir-opt/building/index_array_and_slice.index_slice.built.after.mir32
-rw-r--r--tests/mir-opt/building/index_array_and_slice.rs71
-rw-r--r--tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff11
-rw-r--r--tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff11
-rw-r--r--tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff11
-rw-r--r--tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff11
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff13
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff13
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff13
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff13
-rw-r--r--tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff11
-rw-r--r--tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff11
-rw-r--r--tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff11
-rw-r--r--tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff11
-rw-r--r--tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff11
-rw-r--r--tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff11
-rw-r--r--tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff11
-rw-r--r--tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff11
-rw-r--r--tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff7
-rw-r--r--tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff7
-rw-r--r--tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff7
-rw-r--r--tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff7
-rw-r--r--tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-abort.diff12
-rw-r--r--tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff12
-rw-r--r--tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff11
-rw-r--r--tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff11
-rw-r--r--tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff11
-rw-r--r--tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff11
-rw-r--r--tests/mir-opt/dataflow-const-prop/array_index.rs3
-rw-r--r--tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff11
-rw-r--r--tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff11
-rw-r--r--tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff11
-rw-r--r--tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff11
-rw-r--r--tests/mir-opt/dataflow-const-prop/large_array_index.rs2
-rw-r--r--tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff11
-rw-r--r--tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff11
-rw-r--r--tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff11
-rw-r--r--tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff11
-rw-r--r--tests/mir-opt/dataflow-const-prop/repeat.rs3
-rw-r--r--tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff77
-rw-r--r--tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff77
-rw-r--r--tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff77
-rw-r--r--tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff77
-rw-r--r--tests/mir-opt/dataflow-const-prop/slice_len.rs34
-rw-r--r--tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff4
-rw-r--r--tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff4
-rw-r--r--tests/mir-opt/gvn.constant_index_overflow.GVN.panic-abort.diff4
-rw-r--r--tests/mir-opt/gvn.constant_index_overflow.GVN.panic-unwind.diff4
-rw-r--r--tests/mir-opt/gvn.dedup_multiple_bounds_checks_lengths.GVN.panic-abort.diff72
-rw-r--r--tests/mir-opt/gvn.dedup_multiple_bounds_checks_lengths.GVN.panic-unwind.diff72
-rw-r--r--tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff48
-rw-r--r--tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff48
-rw-r--r--tests/mir-opt/gvn.rs20
-rw-r--r--tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-abort.diff302
-rw-r--r--tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-unwind.diff302
-rw-r--r--tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-abort.diff77
-rw-r--r--tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-unwind.diff77
-rw-r--r--tests/mir-opt/instsimplify/combine_array_len.rs15
-rw-r--r--tests/mir-opt/issue_72181.foo.built.after.mir9
-rw-r--r--tests/mir-opt/issue_72181.main.built.after.mir9
-rw-r--r--tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff32
-rw-r--r--tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff32
-rw-r--r--tests/mir-opt/issue_91633.foo.built.after.mir12
-rw-r--r--tests/mir-opt/issue_91633.fun.built.after.mir2
-rw-r--r--tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff20
-rw-r--r--tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff20
-rw-r--r--tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff43
-rw-r--r--tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff43
-rw-r--r--tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-unwind.diff2
-rw-r--r--tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir47
-rw-r--r--tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir47
-rw-r--r--tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir4
-rw-r--r--tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir4
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff26
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff26
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff26
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff26
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-abort.diff38
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff38
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-abort.diff38
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff38
-rw-r--r--tests/mir-opt/pre-codegen/slice_index.rs2
-rw-r--r--tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-abort.mir2
-rw-r--r--tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir30
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir30
-rw-r--r--tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff9
-rw-r--r--tests/run-make/cat-and-grep-sanity-check/Makefile50
-rw-r--r--tests/run-make/crate-circular-deps-link/c.rs6
-rw-r--r--tests/run-make/fmt-write-bloat/main.rs6
-rw-r--r--tests/run-make/glibc-symbols-x86_64-unknown-linux-gnu/rmake.rs112
-rw-r--r--tests/run-make/jobserver-error/Makefile17
-rw-r--r--tests/run-make/jobserver-error/cannot_open_fd.stderr2
-rw-r--r--tests/run-make/jobserver-error/rmake.rs47
-rw-r--r--tests/run-make/llvm-location-discriminator-limit-dummy-span/main.rs3
-rw-r--r--tests/run-make/llvm-location-discriminator-limit-dummy-span/other.rs1
-rw-r--r--tests/run-make/llvm-location-discriminator-limit-dummy-span/proc.rs7
-rw-r--r--tests/run-make/llvm-location-discriminator-limit-dummy-span/rmake.rs65
-rw-r--r--tests/run-make/no-alloc-shim/foo.rs2
-rw-r--r--tests/run-make/sepcomp-inlining/foo.rs5
-rw-r--r--tests/rustdoc-gui/huge-collection-of-constants.goml4
-rw-r--r--tests/rustdoc-gui/item-name-wrap.goml10
-rw-r--r--tests/rustdoc-gui/item-summary-table.goml4
-rw-r--r--tests/rustdoc-gui/label-next-to-symbol.goml36
-rw-r--r--tests/rustdoc-gui/links-color.goml4
-rw-r--r--tests/rustdoc-gui/module-items-font.goml28
-rw-r--r--tests/rustdoc-gui/sidebar.goml10
-rw-r--r--tests/rustdoc-gui/unsafe-fn.goml2
-rw-r--r--tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.rs1
-rw-r--r--tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.stdout2
-rw-r--r--tests/rustdoc-ui/invalid_const_in_lifetime_position.rs2
-rw-r--r--tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr9
-rw-r--r--tests/rustdoc-ui/issues/ice-generic-type-alias-105742.rs4
-rw-r--r--tests/rustdoc-ui/issues/ice-generic-type-alias-105742.stderr11
-rw-r--r--tests/rustdoc/anonymous-reexport-108931.rs4
-rw-r--r--tests/rustdoc/anonymous-reexport.rs2
-rw-r--r--tests/rustdoc/attributes-inlining-108281.rs6
-rw-r--r--tests/rustdoc/cfg_doc_reexport.rs4
-rw-r--r--tests/rustdoc/deprecated.rs7
-rw-r--r--tests/rustdoc/display-hidden-items.rs16
-rw-r--r--tests/rustdoc/doc-cfg.rs6
-rw-r--r--tests/rustdoc/doc-hidden-reexports-109449.rs6
-rw-r--r--tests/rustdoc/double-hyphen-to-dash.rs2
-rw-r--r--tests/rustdoc/duplicate-cfg.rs4
-rw-r--r--tests/rustdoc/footnote-in-summary.rs4
-rw-r--r--tests/rustdoc/glob-reexport-attribute-merge-120487.rs4
-rw-r--r--tests/rustdoc/glob-reexport-attribute-merge-doc-auto-cfg.rs4
-rw-r--r--tests/rustdoc/glob-shadowing-const.rs4
-rw-r--r--tests/rustdoc/glob-shadowing.rs18
-rw-r--r--tests/rustdoc/impl-on-ty-alias-issue-119015.rs4
-rw-r--r--tests/rustdoc/inline-private-with-intermediate-doc-hidden.rs2
-rw-r--r--tests/rustdoc/inline_cross/inline_hidden.rs8
-rw-r--r--tests/rustdoc/inline_cross/macros.rs6
-rw-r--r--tests/rustdoc/internal.rs2
-rw-r--r--tests/rustdoc/intra-doc/module-scope-name-resolution-55364.rs8
-rw-r--r--tests/rustdoc/item-desc-list-at-start.item-table.html2
-rw-r--r--tests/rustdoc/item-desc-list-at-start.rs7
-rw-r--r--tests/rustdoc/macro-rules-broken-intra-doc-106142.rs17
-rw-r--r--tests/rustdoc/multiple-mods-w-same-name-doc-inline-83375.rs2
-rw-r--r--tests/rustdoc/multiple-mods-w-same-name-doc-inline-last-item-83375.rs2
-rw-r--r--tests/rustdoc/nested-items-issue-111415.rs2
-rw-r--r--tests/rustdoc/overlapping-reexport-105735-2.rs4
-rw-r--r--tests/rustdoc/overlapping-reexport-105735.rs4
-rw-r--r--tests/rustdoc/pub-use-root-path-95873.rs2
-rw-r--r--tests/rustdoc/reexport-cfg.rs8
-rw-r--r--tests/rustdoc/reexport-check.rs4
-rw-r--r--tests/rustdoc/reexport-doc-hidden-inside-private.rs2
-rw-r--r--tests/rustdoc/reexport-of-reexport-108679.rs3
-rw-r--r--tests/rustdoc/reexport-trait-from-hidden-111064.rs2
-rw-r--r--tests/rustdoc/short-docblock.rs11
-rw-r--r--tests/rustdoc/sidebar/sidebar-items.rs2
-rw-r--r--tests/rustdoc/stability.rs6
-rw-r--r--tests/rustdoc/staged-api-deprecated-unstable-32374.rs8
-rw-r--r--tests/rustdoc/summary-header-46377.rs2
-rw-r--r--tests/ui-fulldeps/compiler-calls.rs2
-rw-r--r--tests/ui-fulldeps/obtain-borrowck.rs2
-rw-r--r--tests/ui-fulldeps/run-compiler-twice.rs2
-rw-r--r--tests/ui/array-slice-vec/vec-macro-no-std.rs12
-rw-r--r--tests/ui/associated-consts/associated-const-in-trait.rs4
-rw-r--r--tests/ui/associated-consts/associated-const-in-trait.stderr18
-rw-r--r--tests/ui/associated-item/issue-48027.rs2
-rw-r--r--tests/ui/associated-item/issue-48027.stderr9
-rw-r--r--tests/ui/associated-types/associated-types-in-ambiguous-context.stderr8
-rw-r--r--tests/ui/async-await/async-closures/is-not-fn.current.stderr (renamed from tests/ui/async-await/async-closures/is-not-fn.stderr)8
-rw-r--r--tests/ui/async-await/async-closures/is-not-fn.next.stderr19
-rw-r--r--tests/ui/async-await/async-closures/is-not-fn.rs5
-rw-r--r--tests/ui/async-await/async-fn/dyn-pos.rs2
-rw-r--r--tests/ui/async-await/async-fn/dyn-pos.stderr13
-rw-r--r--tests/ui/async-await/coroutine-desc.stderr1
-rw-r--r--tests/ui/async-await/dont-suggest-missing-await.stderr9
-rw-r--r--tests/ui/async-await/in-trait/dyn-compatibility.rs2
-rw-r--r--tests/ui/async-await/in-trait/dyn-compatibility.stderr9
-rw-r--r--tests/ui/async-await/inference_var_self_argument.rs2
-rw-r--r--tests/ui/async-await/inference_var_self_argument.stderr9
-rw-r--r--tests/ui/async-await/issue-68523-start.rs9
-rw-r--r--tests/ui/async-await/issue-68523-start.stderr9
-rw-r--r--tests/ui/attr-start.rs8
-rw-r--r--tests/ui/borrowck/array-disjoint-borrows-issue-135671.rs30
-rw-r--r--tests/ui/borrowck/borrowck-describe-lvalue.rs1
-rw-r--r--tests/ui/borrowck/borrowck-describe-lvalue.stderr25
-rw-r--r--tests/ui/closures/2229_closure_analysis/diagnostics/arrays.rs6
-rw-r--r--tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr40
-rw-r--r--tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.stderr9
-rw-r--r--tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr22
-rw-r--r--tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.rs4
-rw-r--r--tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr22
-rw-r--r--tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.rs4
-rw-r--r--tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr22
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-102768.rs2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-102768.stderr9
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-80742.stderr2
-rw-r--r--tests/ui/const-generics/issues/index_array_bad_type.rs15
-rw-r--r--tests/ui/const-generics/issues/index_array_bad_type.stderr8
-rw-r--r--tests/ui/consts/const-unstable-intrinsic.stderr10
-rw-r--r--tests/ui/consts/issue-65348.rs4
-rw-r--r--tests/ui/consts/too_generic_eval_ice.stderr10
-rw-r--r--tests/ui/debuginfo/windows_gnu_split_debuginfo_off.rs29
-rw-r--r--tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.aarch64_gl.stderr4
-rw-r--r--tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_g.stderr4
-rw-r--r--tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_gl.stderr4
-rw-r--r--tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_uwp_g.stderr4
-rw-r--r--tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.rs29
-rw-r--r--tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_g.stderr4
-rw-r--r--tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_gl.stderr4
-rw-r--r--tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_uwp_g.stderr4
-rw-r--r--tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.aarch64_gl.stderr4
-rw-r--r--tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_g.stderr4
-rw-r--r--tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_gl.stderr4
-rw-r--r--tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_uwp_g.stderr4
-rw-r--r--tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.rs29
-rw-r--r--tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_g.stderr4
-rw-r--r--tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_gl.stderr4
-rw-r--r--tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_uwp_g.stderr4
-rw-r--r--tests/ui/deprecation/deprecation-lint.stderr5
-rw-r--r--tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.rs2
-rw-r--r--tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr9
-rw-r--r--tests/ui/drop/drop-order-comparisons.e2021.fixed575
-rw-r--r--tests/ui/drop/drop-order-comparisons.e2021.stderr477
-rw-r--r--tests/ui/drop/drop-order-comparisons.rs575
-rw-r--r--tests/ui/drop/lint-if-let-rescope-with-macro.stderr2
-rw-r--r--tests/ui/duplicate/dupe-symbols-7.stderr2
-rw-r--r--tests/ui/duplicate/dupe-symbols-8.stderr2
-rw-r--r--tests/ui/dyn-compatibility/almost-supertrait-associated-type.rs6
-rw-r--r--tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr30
-rw-r--r--tests/ui/dyn-compatibility/associated-consts.curr.stderr18
-rw-r--r--tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr9
-rw-r--r--tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr9
-rw-r--r--tests/ui/dyn-compatibility/avoid-ice-on-warning-2.rs2
-rw-r--r--tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr18
-rw-r--r--tests/ui/dyn-compatibility/avoid-ice-on-warning-3.rs4
-rw-r--r--tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.new.fixed2
-rw-r--r--tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr11
-rw-r--r--tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.rs2
-rw-r--r--tests/ui/dyn-compatibility/bounds.rs2
-rw-r--r--tests/ui/dyn-compatibility/bounds.stderr9
-rw-r--r--tests/ui/dyn-compatibility/gat-incompatible-supertrait.rs18
-rw-r--r--tests/ui/dyn-compatibility/gat-incompatible-supertrait.stderr19
-rw-r--r--tests/ui/dyn-compatibility/generics.curr.stderr45
-rw-r--r--tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr18
-rw-r--r--tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr22
-rw-r--r--tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.rs4
-rw-r--r--tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.stderr36
-rw-r--r--tests/ui/dyn-compatibility/mentions-Self.curr.stderr36
-rw-r--r--tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr18
-rw-r--r--tests/ui/dyn-compatibility/missing-assoc-type.rs2
-rw-r--r--tests/ui/dyn-compatibility/missing-assoc-type.stderr9
-rw-r--r--tests/ui/dyn-compatibility/no-static.curr.stderr33
-rw-r--r--tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr11
-rw-r--r--tests/ui/dyn-compatibility/sized-2.curr.stderr18
-rw-r--r--tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr9
-rw-r--r--tests/ui/dyn-compatibility/sized.curr.stderr18
-rw-r--r--tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr9
-rw-r--r--tests/ui/dyn-compatibility/supertrait-mentions-GAT.rs2
-rw-r--r--tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr9
-rw-r--r--tests/ui/dyn-compatibility/supertrait-mentions-Self.stderr11
-rw-r--r--tests/ui/dyn-compatibility/taint-const-eval.curr.stderr27
-rw-r--r--tests/ui/dyn-compatibility/taint-const-eval.dyn_compatible_for_dispatch.stderr9
-rw-r--r--tests/ui/dyn-compatibility/taint-const-eval.rs6
-rw-r--r--tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.rs6
-rw-r--r--tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr27
-rw-r--r--tests/ui/error-codes/E0038.stderr18
-rw-r--r--tests/ui/error-codes/E0132.rs7
-rw-r--r--tests/ui/error-codes/E0132.stderr9
-rw-r--r--tests/ui/error-codes/E0138.rs8
-rw-r--r--tests/ui/error-codes/E0138.stderr12
-rw-r--r--tests/ui/error-codes/E0225.stderr4
-rw-r--r--tests/ui/error-codes/E0451.stderr2
-rw-r--r--tests/ui/error-codes/E0647.rs9
-rw-r--r--tests/ui/error-codes/E0647.stderr9
-rw-r--r--tests/ui/expr/if/if-let.stderr2
-rw-r--r--tests/ui/extern/extern-prelude-core.rs6
-rw-r--r--tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs6
-rw-r--r--tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr27
-rw-r--r--tests/ui/feature-gates/feature-gate-default-field-values.stderr50
-rw-r--r--tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs4
-rw-r--r--tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr22
-rw-r--r--tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr45
-rw-r--r--tests/ui/feature-gates/feature-gate-start.rs3
-rw-r--r--tests/ui/feature-gates/feature-gate-start.stderr13
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs21
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr117
-rw-r--r--tests/ui/for-loop-while/for-loop-no-std.rs11
-rw-r--r--tests/ui/for-loop-while/while-let-2.stderr2
-rw-r--r--tests/ui/format-no-std.rs9
-rw-r--r--tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.rs2
-rw-r--r--tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr9
-rw-r--r--tests/ui/generic-associated-types/gat-in-trait-path.base.stderr36
-rw-r--r--tests/ui/generic-associated-types/gat-in-trait-path.rs7
-rw-r--r--tests/ui/generic-associated-types/gat-in-trait-path.stderr40
-rw-r--r--tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs4
-rw-r--r--tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr18
-rw-r--r--tests/ui/generic-associated-types/issue-67510-pass.base.stderr9
-rw-r--r--tests/ui/generic-associated-types/issue-67510-pass.rs2
-rw-r--r--tests/ui/generic-associated-types/issue-67510-pass.stderr9
-rw-r--r--tests/ui/generic-associated-types/issue-67510.rs2
-rw-r--r--tests/ui/generic-associated-types/issue-67510.stderr9
-rw-r--r--tests/ui/generic-associated-types/issue-71176.rs6
-rw-r--r--tests/ui/generic-associated-types/issue-71176.stderr33
-rw-r--r--tests/ui/generic-associated-types/issue-76535.base.stderr26
-rw-r--r--tests/ui/generic-associated-types/issue-76535.stderr26
-rw-r--r--tests/ui/generic-associated-types/issue-78671.base.stderr9
-rw-r--r--tests/ui/generic-associated-types/issue-78671.rs2
-rw-r--r--tests/ui/generic-associated-types/issue-78671.stderr9
-rw-r--r--tests/ui/generic-associated-types/issue-79422.base.stderr24
-rw-r--r--tests/ui/generic-associated-types/issue-79422.stderr24
-rw-r--r--tests/ui/generic-associated-types/missing_lifetime_args.rs2
-rw-r--r--tests/ui/generic-associated-types/missing_lifetime_args.stderr9
-rw-r--r--tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs2
-rw-r--r--tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr9
-rw-r--r--tests/ui/generic-associated-types/trait-objects.base.stderr27
-rw-r--r--tests/ui/generic-associated-types/trait-objects.rs6
-rw-r--r--tests/ui/generic-associated-types/trait-objects.stderr27
-rw-r--r--tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.rs4
-rw-r--r--tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr18
-rw-r--r--tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.rs8
-rw-r--r--tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr52
-rw-r--r--tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.current.stderr (renamed from tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.stderr)6
-rw-r--r--tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr29
-rw-r--r--tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs8
-rw-r--r--tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.rs6
-rw-r--r--tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.stderr33
-rw-r--r--tests/ui/impl-trait/in-trait/dyn-compatibility.rs8
-rw-r--r--tests/ui/impl-trait/in-trait/dyn-compatibility.stderr44
-rw-r--r--tests/ui/impl-trait/in-trait/foreign-dyn-error.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr11
-rw-r--r--tests/ui/impl-trait/issue-102605.stderr9
-rw-r--r--tests/ui/inference/issue-72616.stderr13
-rw-r--r--tests/ui/inference/issue-72690.stderr9
-rw-r--r--tests/ui/issues/issue-18959.stderr45
-rw-r--r--tests/ui/issues/issue-19380.stderr33
-rw-r--r--tests/ui/issues/issue-26056.stderr11
-rw-r--r--tests/ui/issues/issue-33941.current.stderr (renamed from tests/ui/issues/issue-33941.stderr)6
-rw-r--r--tests/ui/issues/issue-33941.next.stderr25
-rw-r--r--tests/ui/issues/issue-33941.rs6
-rw-r--r--tests/ui/issues/issue-50714-1.rs11
-rw-r--r--tests/ui/issues/issue-50714-1.stderr9
-rw-r--r--tests/ui/issues/issue-50781.rs6
-rw-r--r--tests/ui/issues/issue-50781.stderr33
-rw-r--r--tests/ui/issues/issue-9575.rs7
-rw-r--r--tests/ui/issues/issue-9575.stderr12
-rw-r--r--tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr18
-rw-r--r--tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr9
-rw-r--r--tests/ui/lang-items/issue-19660.rs15
-rw-r--r--tests/ui/lang-items/issue-19660.stderr4
-rw-r--r--tests/ui/lang-items/lang-item-missing.rs9
-rw-r--r--tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs15
-rw-r--r--tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr8
-rw-r--r--tests/ui/layout/reprc-power-alignment.rs152
-rw-r--r--tests/ui/layout/reprc-power-alignment.stderr112
-rw-r--r--tests/ui/layout/valid_range_oob.stderr2
-rw-r--r--tests/ui/lint/clashing-extern-fn.rs1
-rw-r--r--tests/ui/lint/clashing-extern-fn.stderr22
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr4
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr10
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr4
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr4
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr4
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr4
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr16
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/types.stderr34
-rw-r--r--tests/ui/lint/dead-code/lint-dead-code-2.rs11
-rw-r--r--tests/ui/lint/dead-code/lint-dead-code-2.stderr10
-rw-r--r--tests/ui/lint/wide_pointer_comparisons.stderr2
-rw-r--r--tests/ui/macros/not-utf8.rs2
-rw-r--r--tests/ui/macros/not-utf8.stderr9
-rw-r--r--tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs4
-rw-r--r--tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs4
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.both.stderr169
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.classic.stderr199
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs83
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.structural.stderr180
-rw-r--r--tests/ui/mir/lint/storage-live.stderr2
-rw-r--r--tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed12
-rw-r--r--tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.stderr (renamed from tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.stderr)4
-rw-r--r--tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.fixed5
-rw-r--r--tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr24
-rw-r--r--tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs13
-rw-r--r--tests/ui/modules/path-no-file-name.rs2
-rw-r--r--tests/ui/modules/path-no-file-name.stderr2
-rw-r--r--tests/ui/parser/issues/issue-5806.rs2
-rw-r--r--tests/ui/parser/issues/issue-5806.stderr2
-rw-r--r--tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr4
-rw-r--r--tests/ui/parser/mod_file_with_path_attr.rs2
-rw-r--r--tests/ui/parser/mod_file_with_path_attr.stderr2
-rw-r--r--tests/ui/pattern/no_ref_mut_behind_and.rs9
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic.stderr (renamed from tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.stderr)4
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.rs (renamed from tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.rs)5
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural.stderr25
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.classic.stderr58
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.rs23
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.structural.stderr58
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/feature-gate-ref_pat_eat_one_layer_2024.rs (renamed from tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs)0
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/feature-gate-ref_pat_eat_one_layer_2024.stderr (renamed from tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr)0
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.classic.stderr23
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs18
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.structural.stderr23
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic.stderr111
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs46
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural.stderr89
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic.fixed (renamed from tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.fixed)6
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic.stderr (renamed from tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.stderr)10
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.rs (renamed from tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs)6
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.fixed33
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.stderr43
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021.rs (renamed from tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.rs)6
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021_fail.rs (renamed from tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021_fail.rs)0
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021_fail.stderr (renamed from tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021_fail.stderr)0
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/trait-selection-sanity.rs30
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/trait-selection-sanity.without_impl.stderr16
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs (renamed from tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs)41
-rw-r--r--tests/ui/pattern/usefulness/issue-82772-match-box-as-struct.stderr2
-rw-r--r--tests/ui/print_type_sizes/anonymous.rs7
-rw-r--r--tests/ui/privacy/privacy1.rs4
-rw-r--r--tests/ui/privacy/privacy2.rs4
-rw-r--r--tests/ui/privacy/privacy3.rs4
-rw-r--r--tests/ui/privacy/privacy4.rs4
-rw-r--r--tests/ui/privacy/private-struct-field-ctor.stderr2
-rw-r--r--tests/ui/privacy/private-struct-field-pattern.stderr2
-rw-r--r--tests/ui/privacy/restricted/struct-literal-field.stderr2
-rw-r--r--tests/ui/privacy/union-field-privacy-1.stderr2
-rw-r--r--tests/ui/proc-macro/inner-attr-non-inline-mod.rs1
-rw-r--r--tests/ui/proc-macro/inner-attr-non-inline-mod.stderr35
-rw-r--r--tests/ui/proc-macro/inner-attr-non-inline-mod.stdout30
-rw-r--r--tests/ui/proc-macro/proc-macro-gates.rs1
-rw-r--r--tests/ui/proc-macro/proc-macro-gates.stderr19
-rw-r--r--tests/ui/resolve/auxiliary/fake_matches.rs13
-rw-r--r--tests/ui/resolve/const-with-typo-in-pattern-binding-ice-135289.rs17
-rw-r--r--tests/ui/resolve/issue-3907-2.stderr9
-rw-r--r--tests/ui/resolve/multiple_definitions_attribute_merging.stderr2
-rw-r--r--tests/ui/resolve/proc_macro_generated_packed.stderr2
-rw-r--r--tests/ui/resolve/resolve-issue-135614-assoc-const.import_trait_associated_functions.stderr19
-rw-r--r--tests/ui/resolve/resolve-issue-135614-assoc-const.normal.stderr30
-rw-r--r--tests/ui/resolve/resolve-issue-135614-assoc-const.rs30
-rw-r--r--tests/ui/resolve/resolve-issue-135614.normal.stderr13
-rw-r--r--tests/ui/resolve/resolve-issue-135614.rs15
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.rs12
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.stderr33
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.rs16
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.stderr11
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.rs14
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.stderr20
-rw-r--r--tests/ui/rfcs/rfc-2091-track-caller/error-with-start.rs7
-rw-r--r--tests/ui/rfcs/rfc-2091-track-caller/error-with-start.stderr10
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.rs9
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.stderr11
-rw-r--r--tests/ui/runtime/native-print-no-runtime.rs9
-rw-r--r--tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs15
-rw-r--r--tests/ui/runtime/running-with-no-runtime.rs6
-rw-r--r--tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed11
-rw-r--r--tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs11
-rw-r--r--tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr27
-rw-r--r--tests/ui/sanitizer/memory-eager.rs6
-rw-r--r--tests/ui/sanitizer/memory-passing.rs6
-rw-r--r--tests/ui/sanitizer/memory.rs8
-rw-r--r--tests/ui/self/arbitrary-self-types-dyn-incompatible.curr.stderr22
-rw-r--r--tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr11
-rw-r--r--tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.stderr5
-rw-r--r--tests/ui/stable-mir-print/operands.stdout294
-rw-r--r--tests/ui/statics/unsizing-wfcheck-issue-127299.rs6
-rw-r--r--tests/ui/statics/unsizing-wfcheck-issue-127299.stderr27
-rw-r--r--tests/ui/structs/default-field-values/empty-struct.rs21
-rw-r--r--tests/ui/structs/default-field-values/empty-struct.stderr26
-rw-r--r--tests/ui/structs/default-field-values/non-exhaustive-ctor.disabled.stderr86
-rw-r--r--tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.fixed28
-rw-r--r--tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.stderr25
-rw-r--r--tests/ui/structs/default-field-values/non-exhaustive-ctor.rs28
-rw-r--r--tests/ui/structs/default-field-values/visibility.rs42
-rw-r--r--tests/ui/structs/default-field-values/visibility.stderr61
-rw-r--r--tests/ui/suggestions/dyn-incompatible-trait-references-self.rs4
-rw-r--r--tests/ui/suggestions/dyn-incompatible-trait-references-self.stderr18
-rw-r--r--tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.rs4
-rw-r--r--tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr18
-rw-r--r--tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs4
-rw-r--r--tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr18
-rw-r--r--tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.fixed2
-rw-r--r--tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.rs2
-rw-r--r--tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr9
-rw-r--r--tests/ui/suggestions/issue-116434-2015.rs4
-rw-r--r--tests/ui/suggestions/issue-116434-2015.stderr18
-rw-r--r--tests/ui/suggestions/issue-98500.rs2
-rw-r--r--tests/ui/suggestions/issue-98500.stderr9
-rw-r--r--tests/ui/test-attrs/test-runner-hides-start.rs7
-rw-r--r--tests/ui/traits/alias/generic-default-in-dyn.rs4
-rw-r--r--tests/ui/traits/alias/generic-default-in-dyn.stderr32
-rw-r--r--tests/ui/traits/alias/no-duplicates.stderr234
-rw-r--r--tests/ui/traits/alias/no-extra-traits.stderr328
-rw-r--r--tests/ui/traits/alias/object-fail.rs2
-rw-r--r--tests/ui/traits/alias/object-fail.stderr16
-rw-r--r--tests/ui/traits/alias/self-in-const-generics.rs2
-rw-r--r--tests/ui/traits/alias/self-in-const-generics.stderr17
-rw-r--r--tests/ui/traits/alias/self-in-generics.rs2
-rw-r--r--tests/ui/traits/alias/self-in-generics.stderr19
-rw-r--r--tests/ui/traits/bad-sized.stderr8
-rw-r--r--tests/ui/traits/issue-20692.rs4
-rw-r--r--tests/ui/traits/issue-20692.stderr18
-rw-r--r--tests/ui/traits/issue-28576.rs2
-rw-r--r--tests/ui/traits/issue-28576.stderr14
-rw-r--r--tests/ui/traits/issue-38404.rs6
-rw-r--r--tests/ui/traits/issue-38404.stderr33
-rw-r--r--tests/ui/traits/issue-38604.rs4
-rw-r--r--tests/ui/traits/issue-38604.stderr22
-rw-r--r--tests/ui/traits/issue-72410.rs2
-rw-r--r--tests/ui/traits/issue-72410.stderr9
-rw-r--r--tests/ui/traits/item-privacy.rs4
-rw-r--r--tests/ui/traits/item-privacy.stderr11
-rw-r--r--tests/ui/traits/missing-for-type-in-impl.e2015.stderr9
-rw-r--r--tests/ui/traits/missing-for-type-in-impl.rs2
-rw-r--r--tests/ui/traits/next-solver/diagnostics/alias_relate_error_uses_structurally_normalize.rs28
-rw-r--r--tests/ui/traits/next-solver/diagnostics/alias_relate_error_uses_structurally_normalize.stderr17
-rw-r--r--tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.current.stderr17
-rw-r--r--tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.next.stderr17
-rw-r--r--tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.rs28
-rw-r--r--tests/ui/traits/next-solver/non-wf-in-coerce-pointers.rs17
-rw-r--r--tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr39
-rw-r--r--tests/ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs21
-rw-r--r--tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs6
-rw-r--r--tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr33
-rw-r--r--tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs5
-rw-r--r--tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr28
-rw-r--r--tests/ui/traits/object/macro-matcher.rs2
-rw-r--r--tests/ui/traits/object/macro-matcher.stderr9
-rw-r--r--tests/ui/traits/object/safety.stderr22
-rw-r--r--tests/ui/traits/test-2.stderr39
-rw-r--r--tests/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr13
-rw-r--r--tests/ui/typeck/bad-index-due-to-nested.current.stderr (renamed from tests/ui/typeck/bad-index-due-to-nested.stderr)12
-rw-r--r--tests/ui/typeck/bad-index-due-to-nested.next.stderr76
-rw-r--r--tests/ui/typeck/bad-index-due-to-nested.rs7
-rw-r--r--tests/ui/typeck/issue-82772.stderr6
-rw-r--r--tests/ui/union/union-derive-eq.current.stderr (renamed from tests/ui/union/union-derive-eq.stderr)2
-rw-r--r--tests/ui/union/union-derive-eq.next.stderr19
-rw-r--r--tests/ui/union/union-derive-eq.rs16
-rw-r--r--tests/ui/unpretty/staged-api-invalid-path-108697.stderr2
-rw-r--r--tests/ui/use/use.rs5
-rw-r--r--tests/ui/wf/issue-87495.rs2
-rw-r--r--tests/ui/wf/issue-87495.stderr9
-rw-r--r--tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr33
-rw-r--r--tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr33
-rw-r--r--tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr26
-rw-r--r--tests/ui/wf/wf-dyn-incompatible.stderr9
-rw-r--r--tests/ui/wf/wf-fn-where-clause.stderr9
-rw-r--r--tests/ui/wf/wf-trait-fn-arg.current.stderr (renamed from tests/ui/wf/wf-trait-fn-arg.stderr)8
-rw-r--r--tests/ui/wf/wf-trait-fn-arg.next.stderr14
-rw-r--r--tests/ui/wf/wf-trait-fn-arg.rs16
-rw-r--r--tests/ui/wf/wf-trait-fn-ret.current.stderr (renamed from tests/ui/wf/wf-trait-fn-ret.stderr)8
-rw-r--r--tests/ui/wf/wf-trait-fn-ret.next.stderr14
-rw-r--r--tests/ui/wf/wf-trait-fn-ret.rs15
-rw-r--r--tests/ui/wf/wf-trait-fn-where-clause.current.stderr19
-rw-r--r--tests/ui/wf/wf-trait-fn-where-clause.next.stderr14
-rw-r--r--tests/ui/wf/wf-trait-fn-where-clause.rs23
-rw-r--r--tests/ui/wf/wf-trait-fn-where-clause.stderr19
-rw-r--r--tests/ui/where-clauses/where-clauses-method-unsatisfied.current.stderr (renamed from tests/ui/where-clauses/where-clauses-method-unsatisfied.stderr)11
-rw-r--r--tests/ui/where-clauses/where-clauses-method-unsatisfied.next.stderr23
-rw-r--r--tests/ui/where-clauses/where-clauses-method-unsatisfied.rs10
-rw-r--r--tests/ui/where-clauses/where-clauses-unsatisfied.current.stderr (renamed from tests/ui/where-clauses/where-clauses-unsatisfied.stderr)11
-rw-r--r--tests/ui/where-clauses/where-clauses-unsatisfied.next.stderr23
-rw-r--r--tests/ui/where-clauses/where-clauses-unsatisfied.rs11
-rw-r--r--triagebot.toml1
1374 files changed, 24201 insertions, 12384 deletions
diff --git a/.github/ISSUE_TEMPLATE/bootstrap.md b/.github/ISSUE_TEMPLATE/bootstrap.md
new file mode 100644
index 00000000000..8d72eae8593
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bootstrap.md
@@ -0,0 +1,70 @@
+---
+name: Bootstrap (Rust Build System) Report
+about: Issues encountered on bootstrap build system
+labels: C-bug, T-bootstrap
+---
+
+<!--
+Thank you for submitting a bootstrap report! Please provide detailed information to help us reproduce and diagnose the issue.
+-->
+
+### Summary
+
+<!--
+Provide a brief description of the problem you are experiencing.
+-->
+
+### Command used
+
+```sh
+<command>
+```
+
+### Expected behaviour
+
+<!--
+Describe what you expected to happen.
+-->
+
+### Actual behaviour
+
+<!--
+Describe what actually happened.
+-->
+
+### Bootstrap configuration (config.toml)
+```toml
+<config>
+```
+
+### Operating system
+
+<!--
+e.g., Ubuntu 22.04, macOS 12, Windows 10
+-->
+
+### HEAD
+
+<!--
+Output of `git rev-parse HEAD` command, or content of the `git-commit-hash` file if using a tarball source.
+-->
+
+### Additional context
+<!--
+Include any other relevant information (e.g., if you have custom patches or modifications on the project).
+-->
+
+
+<!--
+Include the complete build log in the section below.
+Enable backtrace and verbose mode if possible for more detailed information e.g., with `RUST_BACKTRACE=1 ./x build -v`.
+-->
+<details><summary>Build Log</summary>
+<p>
+
+```txt
+<log>
+```
+
+</p>
+</details>
diff --git a/.gitignore b/.gitignore
index f84a3704ca9..ddc8dad95e8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -83,6 +83,7 @@ __pycache__/
 node_modules
 package-lock.json
 package.json
+/src/doc/rustc-dev-guide/mermaid.min.js
 
 ## Rustdoc GUI tests
 tests/rustdoc-gui/src/**.lock
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index eeff563d8ec..a5ddff595f5 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -12,6 +12,15 @@ Documentation for contributing to the compiler or tooling is located in the [Gui
 Development][rustc-dev-guide], commonly known as the [rustc-dev-guide]. Documentation for the
 standard library in the [Standard library developers Guide][std-dev-guide], commonly known as the [std-dev-guide].
 
+## Making changes to subtrees and submodules
+
+For submodules, changes need to be made against the repository corresponding the
+submodule, and not the main `rust-lang/rust` repository.
+
+For subtrees, prefer sending a PR against the subtree's repository if it does
+not need to be made against the main `rust-lang/rust` repostory (e.g. a
+rustc-dev-guide change that does not accompany a compiler change).
+
 ## About the [rustc-dev-guide]
 
 The [rustc-dev-guide] is meant to help document how rustc –the Rust compiler– works,
diff --git a/Cargo.lock b/Cargo.lock
index a08d43a014c..10889139e8d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -172,11 +172,12 @@ dependencies = [
 
 [[package]]
 name = "anstyle-wincon"
-version = "3.0.6"
+version = "3.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
+checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
 dependencies = [
  "anstyle",
+ "once_cell",
  "windows-sys 0.59.0",
 ]
 
@@ -254,9 +255,9 @@ dependencies = [
 
 [[package]]
 name = "bitflags"
-version = "2.7.0"
+version = "2.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be"
+checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
 
 [[package]]
 name = "blake3"
@@ -450,9 +451,9 @@ dependencies = [
 
 [[package]]
 name = "chrono-tz"
-version = "0.10.0"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd6dd8046d00723a59a2f8c5f295c515b9bb9a331ee4f8f3d4dd49e428acd3b6"
+checksum = "9c6ac4f2c0bf0f44e9161aec9675e1050aa4a530663c4a9e37e108fa948bca9f"
 dependencies = [
  "chrono",
  "chrono-tz-build",
@@ -733,7 +734,7 @@ dependencies = [
  "tracing-subscriber",
  "unified-diff",
  "walkdir",
- "windows",
+ "windows 0.59.0",
 ]
 
 [[package]]
@@ -1223,7 +1224,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c"
 dependencies = [
  "crc32fast",
- "miniz_oxide 0.8.2",
+ "miniz_oxide 0.8.3",
 ]
 
 [[package]]
@@ -1524,7 +1525,6 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
 dependencies = [
  "ahash",
  "allocator-api2",
- "serde",
 ]
 
 [[package]]
@@ -1534,6 +1534,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
 dependencies = [
  "foldhash",
+ "serde",
 ]
 
 [[package]]
@@ -1954,9 +1955,9 @@ dependencies = [
 
 [[package]]
 name = "js-sys"
-version = "0.3.76"
+version = "0.3.77"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7"
+checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
 dependencies = [
  "once_cell",
  "wasm-bindgen",
@@ -2152,9 +2153,9 @@ dependencies = [
 
 [[package]]
 name = "log"
-version = "0.4.22"
+version = "0.4.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
 
 [[package]]
 name = "lzma-sys"
@@ -2317,9 +2318,9 @@ dependencies = [
 
 [[package]]
 name = "miniz_oxide"
-version = "0.8.2"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394"
+checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924"
 dependencies = [
  "adler2",
 ]
@@ -3574,7 +3575,7 @@ dependencies = [
  "thorin-dwp",
  "tracing",
  "wasm-encoder 0.219.1",
- "windows",
+ "windows 0.59.0",
 ]
 
 [[package]]
@@ -3632,7 +3633,7 @@ dependencies = [
  "tempfile",
  "thin-vec",
  "tracing",
- "windows",
+ "windows 0.59.0",
 ]
 
 [[package]]
@@ -3694,7 +3695,7 @@ dependencies = [
  "shlex",
  "time",
  "tracing",
- "windows",
+ "windows 0.59.0",
 ]
 
 [[package]]
@@ -3747,7 +3748,7 @@ dependencies = [
  "termcolor",
  "termize",
  "tracing",
- "windows",
+ "windows 0.59.0",
 ]
 
 [[package]]
@@ -4259,7 +4260,6 @@ dependencies = [
  "rustc_serialize",
  "rustc_type_ir",
  "rustc_type_ir_macros",
- "smallvec",
  "tracing",
 ]
 
@@ -4480,7 +4480,7 @@ dependencies = [
  "smallvec",
  "termize",
  "tracing",
- "windows",
+ "windows 0.59.0",
 ]
 
 [[package]]
@@ -5183,7 +5183,7 @@ checksum = "355dbe4f8799b304b05e1b0f05fc59b2a18d36645cf169607da45bde2f69a1be"
 dependencies = [
  "core-foundation-sys",
  "libc",
- "windows",
+ "windows 0.57.0",
 ]
 
 [[package]]
@@ -5836,18 +5836,18 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
 
 [[package]]
 name = "uuid"
-version = "1.11.1"
+version = "1.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b913a3b5fe84142e269d63cc62b64319ccaf89b748fc31fe025177f767a756c4"
+checksum = "744018581f9a3454a9e15beb8a33b017183f1e7c0cd170232a2d1453b23a51c4"
 dependencies = [
  "getrandom",
 ]
 
 [[package]]
 name = "valuable"
-version = "0.1.0"
+version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
+checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
 
 [[package]]
 name = "vcpkg"
@@ -5879,26 +5879,27 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasi-preview1-component-adapter-provider"
-version = "24.0.1"
+version = "29.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f76d9fa52234153eeb40b088de91a8c13dc28a912cf6f31cd89ca4bac9024e0"
+checksum = "dcd9f21bbde82ba59e415a8725e6ad0d0d7e9e460b1a3ccbca5bdee952c1a324"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.99"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396"
+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
 dependencies = [
  "cfg-if",
  "once_cell",
+ "rustversion",
  "wasm-bindgen-macro",
 ]
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.99"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79"
+checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
 dependencies = [
  "bumpalo",
  "log",
@@ -5910,9 +5911,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.99"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe"
+checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -5920,9 +5921,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.99"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
+checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -5933,15 +5934,18 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.99"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
+checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+dependencies = [
+ "unicode-ident",
+]
 
 [[package]]
 name = "wasm-component-ld"
-version = "0.5.11"
+version = "0.5.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2b05c3820968b335f10e703218459e4fd2cc91fdfc8f7936a993f1aacaa0938"
+checksum = "580305a8e3f1b7a79859a8db897de643533b2851c5eb080fe5800233f16dec88"
 dependencies = [
  "anyhow",
  "clap",
@@ -5949,7 +5953,7 @@ dependencies = [
  "libc",
  "tempfile",
  "wasi-preview1-component-adapter-provider",
- "wasmparser 0.219.1",
+ "wasmparser 0.223.0",
  "wat",
  "windows-sys 0.59.0",
  "winsplit",
@@ -5986,9 +5990,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-metadata"
-version = "0.219.1"
+version = "0.223.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2af5a8e37a5e996861e1813f8de30911c47609c9ff51a7284f7dbd754dc3a9f3"
+checksum = "5c730c3379d3d20e5a0245b0724b924483e853588ca8fba547c1e21f19e7d735"
 dependencies = [
  "anyhow",
  "indexmap",
@@ -5996,8 +6000,9 @@ dependencies = [
  "serde_derive",
  "serde_json",
  "spdx",
- "wasm-encoder 0.219.1",
- "wasmparser 0.219.1",
+ "url",
+ "wasm-encoder 0.223.0",
+ "wasmparser 0.223.0",
 ]
 
 [[package]]
@@ -6006,12 +6011,8 @@ version = "0.219.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5c771866898879073c53b565a6c7b49953795159836714ac56a5befb581227c5"
 dependencies = [
- "ahash",
  "bitflags",
- "hashbrown 0.14.5",
  "indexmap",
- "semver",
- "serde",
 ]
 
 [[package]]
@@ -6030,8 +6031,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d5a99faceb1a5a84dd6084ec4bfa4b2ab153b5793b43fd8f58b89232634afc35"
 dependencies = [
  "bitflags",
+ "hashbrown 0.15.2",
  "indexmap",
  "semver",
+ "serde",
 ]
 
 [[package]]
@@ -6108,6 +6111,16 @@ dependencies = [
 ]
 
 [[package]]
+name = "windows"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f919aee0a93304be7f62e8e5027811bbba96bcb1de84d6618be56e43f8a32a1"
+dependencies = [
+ "windows-core 0.59.0",
+ "windows-targets 0.53.0",
+]
+
+[[package]]
 name = "windows-bindgen"
 version = "0.58.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6136,13 +6149,26 @@ version = "0.57.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
 dependencies = [
- "windows-implement",
- "windows-interface",
- "windows-result",
+ "windows-implement 0.57.0",
+ "windows-interface 0.57.0",
+ "windows-result 0.1.2",
  "windows-targets 0.52.6",
 ]
 
 [[package]]
+name = "windows-core"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce"
+dependencies = [
+ "windows-implement 0.59.0",
+ "windows-interface 0.59.0",
+ "windows-result 0.3.0",
+ "windows-strings",
+ "windows-targets 0.53.0",
+]
+
+[[package]]
 name = "windows-implement"
 version = "0.57.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6154,6 +6180,17 @@ dependencies = [
 ]
 
 [[package]]
+name = "windows-implement"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.96",
+]
+
+[[package]]
 name = "windows-interface"
 version = "0.57.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6165,6 +6202,17 @@ dependencies = [
 ]
 
 [[package]]
+name = "windows-interface"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb26fd936d991781ea39e87c3a27285081e3c0da5ca0fcbc02d368cc6f52ff01"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.96",
+]
+
+[[package]]
 name = "windows-metadata"
 version = "0.58.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6180,6 +6228,24 @@ dependencies = [
 ]
 
 [[package]]
+name = "windows-result"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d08106ce80268c4067c0571ca55a9b4e9516518eaa1a1fe9b37ca403ae1d1a34"
+dependencies = [
+ "windows-targets 0.53.0",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b888f919960b42ea4e11c2f408fadb55f78a9f236d5eef084103c8ce52893491"
+dependencies = [
+ "windows-targets 0.53.0",
+]
+
+[[package]]
 name = "windows-sys"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6230,7 +6296,7 @@ dependencies = [
  "windows_aarch64_gnullvm 0.52.6",
  "windows_aarch64_msvc 0.52.6",
  "windows_i686_gnu 0.52.6",
- "windows_i686_gnullvm",
+ "windows_i686_gnullvm 0.52.6",
  "windows_i686_msvc 0.52.6",
  "windows_x86_64_gnu 0.52.6",
  "windows_x86_64_gnullvm 0.52.6",
@@ -6238,6 +6304,22 @@ dependencies = [
 ]
 
 [[package]]
+name = "windows-targets"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b"
+dependencies = [
+ "windows_aarch64_gnullvm 0.53.0",
+ "windows_aarch64_msvc 0.53.0",
+ "windows_i686_gnu 0.53.0",
+ "windows_i686_gnullvm 0.53.0",
+ "windows_i686_msvc 0.53.0",
+ "windows_x86_64_gnu 0.53.0",
+ "windows_x86_64_gnullvm 0.53.0",
+ "windows_x86_64_msvc 0.53.0",
+]
+
+[[package]]
 name = "windows_aarch64_gnullvm"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6250,6 +6332,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
 
 [[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
+
+[[package]]
 name = "windows_aarch64_msvc"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6262,6 +6350,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 
 [[package]]
+name = "windows_aarch64_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
+
+[[package]]
 name = "windows_i686_gnu"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6274,12 +6368,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
 
 [[package]]
+name = "windows_i686_gnu"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
+
+[[package]]
 name = "windows_i686_gnullvm"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
 
 [[package]]
+name = "windows_i686_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
+
+[[package]]
 name = "windows_i686_msvc"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6292,6 +6398,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 
 [[package]]
+name = "windows_i686_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
+
+[[package]]
 name = "windows_x86_64_gnu"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6304,6 +6416,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
 
 [[package]]
+name = "windows_x86_64_gnu"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
+
+[[package]]
 name = "windows_x86_64_gnullvm"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6316,6 +6434,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
 
 [[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
+
+[[package]]
 name = "windows_x86_64_msvc"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6328,6 +6452,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
+name = "windows_x86_64_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
+
+[[package]]
 name = "winnow"
 version = "0.5.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6344,9 +6474,9 @@ checksum = "3ab703352da6a72f35c39a533526393725640575bb211f61987a2748323ad956"
 
 [[package]]
 name = "wit-component"
-version = "0.219.1"
+version = "0.223.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad1673163c0cb14a6a19ddbf44dd4efe6f015ec1ebb8156710ac32501f19fba2"
+checksum = "c10ed2aeee4c8ec5715875f62f4a3de3608d6987165c116810d8c2908aa9d93b"
 dependencies = [
  "anyhow",
  "bitflags",
@@ -6355,17 +6485,17 @@ dependencies = [
  "serde",
  "serde_derive",
  "serde_json",
- "wasm-encoder 0.219.1",
+ "wasm-encoder 0.223.0",
  "wasm-metadata",
- "wasmparser 0.219.1",
+ "wasmparser 0.223.0",
  "wit-parser",
 ]
 
 [[package]]
 name = "wit-parser"
-version = "0.219.1"
+version = "0.223.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a86f669283257e8e424b9a4fc3518e3ade0b95deb9fbc0f93a1876be3eda598"
+checksum = "92772f4dcacb804b275981eea1d920b12b377993b53307f1e33d87404e080281"
 dependencies = [
  "anyhow",
  "id-arena",
@@ -6376,7 +6506,7 @@ dependencies = [
  "serde_derive",
  "serde_json",
  "unicode-xid",
- "wasmparser 0.219.1",
+ "wasmparser 0.223.0",
 ]
 
 [[package]]
diff --git a/RELEASES.md b/RELEASES.md
index c4b36ed988b..d8d284ca1fa 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -359,7 +359,7 @@ Language
 - [`addr_of(_mut)!` macros and the newly stabilized `&raw (const|mut)` are now safe to use with all static items](https://github.com/rust-lang/rust/pull/125834)
 - [size_of_val_raw: for length 0 this is safe to call](https://github.com/rust-lang/rust/pull/126152/)
 - [Reorder trait bound modifiers *after* `for<...>` binder in trait bounds](https://github.com/rust-lang/rust/pull/127054/)
-- [Stabilize opaque type precise capturing (RFC 3617)](https://github.com/rust-lang/rust/pull/127672)
+- [Stabilize `+ use<'lt>` opaque type precise capturing (RFC 3617)](https://github.com/rust-lang/rust/pull/127672)
 - [Stabilize `&raw const` and `&raw mut` operators (RFC 2582)](https://github.com/rust-lang/rust/pull/127679)
 - [Stabilize unsafe extern blocks (RFC 3484)](https://github.com/rust-lang/rust/pull/127921)
 - [Stabilize nested field access in `offset_of!`](https://github.com/rust-lang/rust/pull/128284)
diff --git a/compiler/rustc_ast/src/entry.rs b/compiler/rustc_ast/src/entry.rs
index ab1413d6080..12cbb3b2a15 100644
--- a/compiler/rustc_ast/src/entry.rs
+++ b/compiler/rustc_ast/src/entry.rs
@@ -18,12 +18,6 @@ pub enum EntryPointType {
     /// fn main() {}
     /// ```
     RustcMainAttr,
-    /// This is a function with the `#[start]` attribute.
-    /// ```ignore (clashes with test entrypoint)
-    /// #[start]
-    /// fn main() {}
-    /// ```
-    Start,
     /// This function is **not** an entrypoint but simply named `main` (not at the root).
     /// This is only used for diagnostics.
     /// ```
@@ -40,9 +34,7 @@ pub fn entry_point_type(
     at_root: bool,
     name: Option<Symbol>,
 ) -> EntryPointType {
-    if attr::contains_name(attrs, sym::start) {
-        EntryPointType::Start
-    } else if attr::contains_name(attrs, sym::rustc_main) {
+    if attr::contains_name(attrs, sym::rustc_main) {
         EntryPointType::RustcMainAttr
     } else if let Some(name) = name
         && name == sym::main
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
index 266e77c0e02..f9fe4938ca8 100644
--- a/compiler/rustc_ast_lowering/src/delegation.rs
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -72,7 +72,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         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).map_or(false, |sig| sig.has_self)
+            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,
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index a76ca6772e5..f31e2c65c79 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -2159,7 +2159,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let path = hir::ExprKind::Path(hir::QPath::TypeRelative(
             self.arena.alloc(self.ty(span, hir::TyKind::Path(qpath))),
             self.arena.alloc(hir::PathSegment::new(
-                Ident::new(name, span),
+                Ident::new(name, self.lower_span(span)),
                 self.next_id(),
                 Res::Err,
             )),
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index 29d4fb9ef25..9cfdbc47495 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -78,24 +78,31 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
 
         // Make sure that the DepNode of some node coincides with the HirId
         // owner of that node.
-        if cfg!(debug_assertions) && hir_id.owner != self.owner {
-            span_bug!(
-                span,
-                "inconsistent HirId at `{:?}` for `{:?}`: \
+        if cfg!(debug_assertions) {
+            if hir_id.owner != self.owner {
+                span_bug!(
+                    span,
+                    "inconsistent HirId at `{:?}` for `{node:?}`: \
                      current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})",
-                self.tcx.sess.source_map().span_to_diagnostic_string(span),
-                node,
-                self.tcx
-                    .definitions_untracked()
-                    .def_path(self.owner.def_id)
-                    .to_string_no_crate_verbose(),
-                self.owner,
-                self.tcx
-                    .definitions_untracked()
-                    .def_path(hir_id.owner.def_id)
-                    .to_string_no_crate_verbose(),
-                hir_id.owner,
-            )
+                    self.tcx.sess.source_map().span_to_diagnostic_string(span),
+                    self.tcx
+                        .definitions_untracked()
+                        .def_path(self.owner.def_id)
+                        .to_string_no_crate_verbose(),
+                    self.owner,
+                    self.tcx
+                        .definitions_untracked()
+                        .def_path(hir_id.owner.def_id)
+                        .to_string_no_crate_verbose(),
+                    hir_id.owner,
+                )
+            }
+            if self.tcx.sess.opts.incremental.is_some()
+                && span.parent().is_none()
+                && !span.is_dummy()
+            {
+                span_bug!(span, "span without a parent: {:#?}, {node:?}", span.data())
+            }
         }
 
         self.nodes[hir_id.local_id] = ParentedNode { parent: self.parent_node, node };
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 61d7da429f8..74870d74150 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1092,6 +1092,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             // this as a special case.
             return self.lower_fn_body(decl, |this| {
                 if attrs.iter().any(|a| a.name_or_empty() == sym::rustc_intrinsic) {
+                    let span = this.lower_span(span);
                     let empty_block = hir::Block {
                         hir_id: this.next_id(),
                         stmts: &[],
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index abd314ae74c..3c78ed0497d 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -375,24 +375,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         expr: &Expr,
         allow_paths: bool,
     ) -> &'hir hir::PatExpr<'hir> {
+        let span = self.lower_span(expr.span);
         let err = |guar| hir::PatExprKind::Lit {
-            lit: self.arena.alloc(respan(self.lower_span(expr.span), LitKind::Err(guar))),
+            lit: self.arena.alloc(respan(span, LitKind::Err(guar))),
             negated: false,
         };
         let kind = match &expr.kind {
             ExprKind::Lit(lit) => {
-                hir::PatExprKind::Lit { lit: self.lower_lit(lit, expr.span), negated: false }
+                hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: false }
             }
             ExprKind::ConstBlock(c) => hir::PatExprKind::ConstBlock(self.lower_const_block(c)),
             ExprKind::IncludedBytes(bytes) => hir::PatExprKind::Lit {
-                lit: self.arena.alloc(respan(
-                    self.lower_span(expr.span),
-                    LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked),
-                )),
+                lit: self
+                    .arena
+                    .alloc(respan(span, LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked))),
                 negated: false,
             },
             ExprKind::Err(guar) => err(*guar),
-            ExprKind::Dummy => span_bug!(expr.span, "lowered ExprKind::Dummy"),
+            ExprKind::Dummy => span_bug!(span, "lowered ExprKind::Dummy"),
             ExprKind::Path(qself, path) if allow_paths => hir::PatExprKind::Path(self.lower_qpath(
                 expr.id,
                 qself,
@@ -403,21 +403,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 None,
             )),
             ExprKind::Unary(UnOp::Neg, inner) if let ExprKind::Lit(lit) = &inner.kind => {
-                hir::PatExprKind::Lit { lit: self.lower_lit(lit, expr.span), negated: true }
+                hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: true }
             }
             _ => {
                 let pattern_from_macro = expr.is_approximately_pattern();
                 let guar = self.dcx().emit_err(ArbitraryExpressionInPattern {
-                    span: expr.span,
+                    span,
                     pattern_from_macro_note: pattern_from_macro,
                 });
                 err(guar)
             }
         };
-        self.arena.alloc(hir::PatExpr {
-            hir_id: self.lower_node_id(expr.id),
-            span: expr.span,
-            kind,
-        })
+        self.arena.alloc(hir::PatExpr { hir_id: self.lower_node_id(expr.id), span, kind })
     }
 }
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 94746212138..80b99f94485 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -83,7 +83,7 @@ impl<'a> PostExpansionVisitor<'a> {
                 feature_err_issue(&self.sess, feature, span, GateIssue::Language, explain).emit();
             }
             Err(abi::AbiDisabled::Unrecognized) => {
-                if self.sess.opts.pretty.map_or(true, |ppm| ppm.needs_hir()) {
+                if self.sess.opts.pretty.is_none_or(|ppm| ppm.needs_hir()) {
                     self.sess.dcx().span_delayed_bug(
                         span,
                         format!(
@@ -230,18 +230,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 }
             }
 
-            ast::ItemKind::Fn(..) => {
-                if attr::contains_name(&i.attrs, sym::start) {
-                    gate!(
-                        &self,
-                        start,
-                        i.span,
-                        "`#[start]` functions are experimental and their signature may change \
-                         over time"
-                    );
-                }
-            }
-
             ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..) => {
                 for attr in attr::filter_by_name(&i.attrs, sym::repr) {
                     for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) {
diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs
index 124f0aa3eff..28c381160b8 100644
--- a/compiler/rustc_attr_parsing/src/attributes/repr.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs
@@ -166,7 +166,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &impl AttributeExt) -> Vec<ReprAttr
                 // the `check_mod_attrs` pass, but this pass doesn't always run
                 // (e.g. if we only pretty-print the source), so we have to gate
                 // the `span_delayed_bug` call as follows:
-                if sess.opts.pretty.map_or(true, |pp| pp.needs_analysis()) {
+                if sess.opts.pretty.is_none_or(|pp| pp.needs_analysis()) {
                     dcx.span_delayed_bug(item.span(), "unrecognized representation hint");
                 }
             }
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index da59f9f9ebd..d020244bf55 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -39,7 +39,9 @@ use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
 use rustc_trait_selection::error_reporting::traits::call_kind::CallKind;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
-use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
+use rustc_trait_selection::traits::{
+    Obligation, ObligationCause, ObligationCtxt, supertrait_def_ids,
+};
 use tracing::{debug, instrument};
 
 use super::explain_borrow::{BorrowExplanation, LaterUseKind};
@@ -658,8 +660,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
             clause.as_trait_clause().is_some_and(|tc| {
                 tc.self_ty().skip_binder().is_param(param.index)
                     && tc.polarity() == ty::PredicatePolarity::Positive
-                    && tcx
-                        .supertrait_def_ids(tc.def_id())
+                    && supertrait_def_ids(tcx, tc.def_id())
                         .flat_map(|trait_did| tcx.associated_items(trait_did).in_definition_order())
                         .any(|item| item.fn_has_self_parameter)
             })
@@ -2480,7 +2481,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                     // To support cases like `|| { v.call(|this| v.get()) }`
                     // FIXME: actually support such cases (need to figure out how to move from the
                     // capture place to original local).
-                    && self.res.as_ref().map_or(true, |(prev_res, _)| prev_res.span.contains(ex.span))
+                    && self.res.as_ref().is_none_or(|(prev_res, _)| prev_res.span.contains(ex.span))
                 {
                     self.res = Some((ex, closure));
                 }
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 5c0c1d0eb86..2656e0bb6a4 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -131,10 +131,10 @@ impl<'tcx> BorrowExplanation<'tcx> {
                     && let Ok(pat) = tcx.sess.source_map().span_to_snippet(pat.span)
                 {
                     suggest_rewrite_if_let(tcx, expr, &pat, init, conseq, alt, err);
-                } else if path_span.map_or(true, |path_span| path_span == var_or_use_span) {
+                } else if path_span.is_none_or(|path_span| path_span == var_or_use_span) {
                     // We can use `var_or_use_span` if either `path_span` is not present, or both
                     // spans are the same.
-                    if borrow_span.map_or(true, |sp| !sp.overlaps(var_or_use_span)) {
+                    if borrow_span.is_none_or(|sp| !sp.overlaps(var_or_use_span)) {
                         err.span_label(
                             var_or_use_span,
                             format!("{borrow_desc}borrow later {message}"),
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index c6e6d962ce5..91dc76f597a 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -829,6 +829,7 @@ use self::ReadOrWrite::{Activation, Read, Reservation, Write};
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 enum ArtificialField {
+    ArrayLength,
     FakeBorrow,
 }
 
@@ -1338,11 +1339,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                 );
             }
 
-            &Rvalue::Discriminant(place) => {
+            &(Rvalue::Len(place) | Rvalue::Discriminant(place)) => {
+                let af = match *rvalue {
+                    Rvalue::Len(..) => Some(ArtificialField::ArrayLength),
+                    Rvalue::Discriminant(..) => None,
+                    _ => unreachable!(),
+                };
                 self.access_place(
                     location,
                     (place, span),
-                    (Shallow(None), Read(ReadKind::Copy)),
+                    (Shallow(af), Read(ReadKind::Copy)),
                     LocalMutationIsAllowed::No,
                     state,
                 );
diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs
index 560b8c0349a..679e111caa9 100644
--- a/compiler/rustc_borrowck/src/places_conflict.rs
+++ b/compiler/rustc_borrowck/src/places_conflict.rs
@@ -203,7 +203,8 @@ fn place_components_conflict<'tcx>(
             let base_ty = base.ty(body, tcx).ty;
 
             match (elem, base_ty.kind(), access) {
-                (_, _, Shallow(Some(ArtificialField::FakeBorrow))) => {
+                (_, _, Shallow(Some(ArtificialField::ArrayLength)))
+                | (_, _, Shallow(Some(ArtificialField::FakeBorrow))) => {
                     // The array length is like additional fields on the
                     // type; it does not overlap any existing data there.
                     // Furthermore, if cannot actually be a prefix of any
diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs
index 0ad91ae51a3..cbcfab1dc3e 100644
--- a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs
+++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs
@@ -300,11 +300,16 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
                 self.consume_operand(location, op);
             }
 
-            &Rvalue::Discriminant(place) => {
+            &(Rvalue::Len(place) | Rvalue::Discriminant(place)) => {
+                let af = match rvalue {
+                    Rvalue::Len(..) => Some(ArtificialField::ArrayLength),
+                    Rvalue::Discriminant(..) => None,
+                    _ => unreachable!(),
+                };
                 self.access_place(
                     location,
                     place,
-                    (Shallow(None), Read(ReadKind::Copy)),
+                    (Shallow(af), Read(ReadKind::Copy)),
                     LocalMutationIsAllowed::No,
                 );
             }
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index 3903c45fda5..bffd9f38334 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -185,7 +185,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 CustomTypeOp::new(
                     |ocx| {
                         let structurally_normalize = |ty| {
-                            ocx.structurally_normalize(
+                            ocx.structurally_normalize_ty(
                                 &ObligationCause::misc(
                                     location.to_locations().span(body),
                                     body.source.def_id().expect_local(),
@@ -230,7 +230,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 ConstraintCategory::Boring,
                 CustomTypeOp::new(
                     |ocx| {
-                        ocx.structurally_normalize(
+                        ocx.structurally_normalize_ty(
                             &ObligationCause::misc(
                                 location.to_locations().span(body),
                                 body.source.def_id().expect_local(),
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index eca8a688ff4..e0196d55f20 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -2235,6 +2235,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
 
             Rvalue::RawPtr(..)
             | Rvalue::ThreadLocalRef(..)
+            | Rvalue::Len(..)
             | Rvalue::Discriminant(..)
             | Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => {}
         }
@@ -2250,6 +2251,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             | Rvalue::Repeat(..)
             | Rvalue::Ref(..)
             | Rvalue::RawPtr(..)
+            | Rvalue::Len(..)
             | Rvalue::Cast(..)
             | Rvalue::ShallowInitBox(..)
             | Rvalue::BinaryOp(..)
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 6071d36f8eb..0918403b855 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -16,6 +16,7 @@
 #![feature(proc_macro_internals)]
 #![feature(proc_macro_quote)]
 #![feature(rustdoc_internals)]
+#![feature(string_from_utf8_lossy_owned)]
 #![feature(try_blocks)]
 #![warn(unreachable_pub)]
 // tidy-alphabetical-end
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index 123b96f6bca..d163da3ddea 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -13,7 +13,7 @@ use rustc_expand::base::{
 use rustc_expand::module::DirOwnership;
 use rustc_lint_defs::BuiltinLintDiag;
 use rustc_parse::parser::{ForceCollect, Parser};
-use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal};
+use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal, utf8_error};
 use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
 use rustc_span::source_map::SourceMap;
 use rustc_span::{Pos, Span, Symbol};
@@ -209,9 +209,10 @@ pub(crate) fn expand_include_str(
                 let interned_src = Symbol::intern(src);
                 MacEager::expr(cx.expr_str(cx.with_def_site_ctxt(bsp), interned_src))
             }
-            Err(_) => {
-                let guar = cx.dcx().span_err(sp, format!("`{path}` wasn't a utf-8 file"));
-                DummyResult::any(sp, guar)
+            Err(utf8err) => {
+                let mut err = cx.dcx().struct_span_err(sp, format!("`{path}` wasn't a utf-8 file"));
+                utf8_error(cx.source_map(), path.as_str(), None, &mut err, utf8err, &bytes[..]);
+                DummyResult::any(sp, err.emit())
             }
         },
         Err(dummy) => dummy,
@@ -273,7 +274,7 @@ fn load_binary_file(
                     .and_then(|path| path.into_os_string().into_string().ok());
 
                 if let Some(new_path) = new_path {
-                    err.span_suggestion(
+                    err.span_suggestion_verbose(
                         path_span,
                         "there is a file with the same name in a different directory",
                         format!("\"{}\"", new_path.replace('\\', "/").escape_debug()),
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 46446598943..31b068bd33d 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -204,11 +204,11 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> {
         ast::mut_visit::walk_item(self, item);
         self.depth -= 1;
 
-        // Remove any #[rustc_main] or #[start] from the AST so it doesn't
+        // Remove any #[rustc_main] from the AST so it doesn't
         // clash with the one we're going to add, but mark it as
         // #[allow(dead_code)] to avoid printing warnings.
         match entry_point_type(&item, self.depth == 0) {
-            EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => {
+            EntryPointType::MainNamed | EntryPointType::RustcMainAttr => {
                 let allow_dead_code = attr::mk_attr_nested_word(
                     &self.sess.psess.attr_id_generator,
                     ast::AttrStyle::Outer,
@@ -217,8 +217,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> {
                     sym::dead_code,
                     self.def_site,
                 );
-                item.attrs
-                    .retain(|attr| !attr.has_name(sym::rustc_main) && !attr.has_name(sym::start));
+                item.attrs.retain(|attr| !attr.has_name(sym::rustc_main));
                 item.attrs.push(allow_dead_code);
             }
             EntryPointType::None | EntryPointType::OtherMain => {}
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index e4c3dd708fd..9c6aad3490d 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,4 +1,4 @@
 [toolchain]
-channel = "nightly-2025-01-10"
+channel = "nightly-2025-01-20"
 components = ["rust-src", "rustc-dev", "llvm-tools"]
 profile = "minimal"
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index e569da90cf7..41aa011e805 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -176,12 +176,11 @@ diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-supp
 index 9607ff02f96..b7d97caf9a2 100644
 --- a/src/tools/run-make-support/src/external_deps/rustdoc.rs
 +++ b/src/tools/run-make-support/src/external_deps/rustdoc.rs
-@@ -34,8 +34,6 @@ pub fn bare() -> Self {
+@@ -34,7 +34,6 @@ pub fn bare() -> Self {
      #[track_caller]
      pub fn new() -> Self {
          let mut cmd = setup_common();
--        let target_rpath_dir = env_var_os("TARGET_RPATH_DIR");
--        cmd.arg(format!("-L{}", target_rpath_dir.to_string_lossy()));
+-        cmd.arg("-L").arg(env_var_os("TARGET_RPATH_DIR"));
          Self { cmd }
      }
 
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 956a024fa4d..34066eb83fc 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -828,6 +828,12 @@ fn codegen_stmt<'tcx>(
                         fx.bcx.ins().nop();
                     }
                 }
+                Rvalue::Len(place) => {
+                    let place = codegen_place(fx, place);
+                    let usize_layout = fx.layout_of(fx.tcx.types.usize);
+                    let len = codegen_array_len(fx, place);
+                    lval.write_cvalue(fx, CValue::by_val(len, usize_layout));
+                }
                 Rvalue::ShallowInitBox(ref operand, content_ty) => {
                     let content_ty = fx.monomorphize(content_ty);
                     let box_layout = fx.layout_of(Ty::new_box(fx.tcx, content_ty));
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index fe578e44770..7d5592daac1 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -333,9 +333,17 @@ fn make_module(sess: &Session, name: String) -> UnwindModule<ObjectModule> {
 
     let mut builder =
         ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap();
+
+    // Disable function sections by default on MSVC as it causes significant slowdowns with link.exe.
+    // Maybe link.exe has exponential behavior when there are many sections with the same name? Also
+    // explicitly disable it on MinGW as rustc already disables it by default on MinGW and as such
+    // isn't tested. If rustc enables it in the future on MinGW, we can re-enable it too once it has
+    // been on MinGW.
+    let default_function_sections = sess.target.function_sections && !sess.target.is_like_windows;
     builder.per_function_section(
-        sess.opts.unstable_opts.function_sections.unwrap_or(sess.target.function_sections),
+        sess.opts.unstable_opts.function_sections.unwrap_or(default_function_sections),
     );
+
     UnwindModule::new(ObjectModule::new(builder), true)
 }
 
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 2e5813556aa..26f14532b45 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -1,4 +1,5 @@
 //! Codegen of intrinsics. This includes `extern "rust-intrinsic"`,
+//! functions marked with the `#[rustc_intrinsic]` attribute
 //! and LLVM intrinsics that have symbol names starting with `llvm.`.
 
 macro_rules! intrinsic_args {
diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs
index e6bf0d5b47e..f6843496895 100644
--- a/compiler/rustc_codegen_cranelift/src/main_shim.rs
+++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs
@@ -1,7 +1,7 @@
 use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
 use rustc_hir::LangItem;
 use rustc_middle::ty::{AssocKind, GenericArg};
-use rustc_session::config::{EntryFnType, sigpipe};
+use rustc_session::config::EntryFnType;
 use rustc_span::{DUMMY_SP, Ident};
 
 use crate::prelude::*;
@@ -14,10 +14,9 @@ pub(crate) fn maybe_create_entry_wrapper(
     is_jit: bool,
     is_primary_cgu: bool,
 ) {
-    let (main_def_id, (is_main_fn, sigpipe)) = match tcx.entry_fn(()) {
+    let (main_def_id, sigpipe) = match tcx.entry_fn(()) {
         Some((def_id, entry_ty)) => (def_id, match entry_ty {
-            EntryFnType::Main { sigpipe } => (true, sigpipe),
-            EntryFnType::Start => (false, sigpipe::DEFAULT),
+            EntryFnType::Main { sigpipe } => sigpipe,
         }),
         None => return,
     };
@@ -31,14 +30,13 @@ pub(crate) fn maybe_create_entry_wrapper(
         return;
     }
 
-    create_entry_fn(tcx, module, main_def_id, is_jit, is_main_fn, sigpipe);
+    create_entry_fn(tcx, module, main_def_id, is_jit, sigpipe);
 
     fn create_entry_fn(
         tcx: TyCtxt<'_>,
         m: &mut dyn Module,
         rust_main_def_id: DefId,
         ignore_lang_start_wrapper: bool,
-        is_main_fn: bool,
         sigpipe: u8,
     ) {
         let main_ret_ty = tcx.fn_sig(rust_main_def_id).no_bound_vars().unwrap().output();
@@ -94,8 +92,8 @@ pub(crate) fn maybe_create_entry_wrapper(
 
             let main_func_ref = m.declare_func_in_func(main_func_id, &mut bcx.func);
 
-            let result = if is_main_fn && ignore_lang_start_wrapper {
-                // regular main fn, but ignoring #[lang = "start"] as we are running in the jit
+            let result = if ignore_lang_start_wrapper {
+                // ignoring #[lang = "start"] as we are running in the jit
                 // FIXME set program arguments somehow
                 let call_inst = bcx.ins().call(main_func_ref, &[]);
                 let call_results = bcx.func.dfg.inst_results(call_inst).to_owned();
@@ -133,7 +131,8 @@ pub(crate) fn maybe_create_entry_wrapper(
                     types::I64 => bcx.ins().sextend(types::I64, res),
                     _ => unimplemented!("16bit systems are not yet supported"),
                 }
-            } else if is_main_fn {
+            } else {
+                // Regular main fn invoked via start lang item.
                 let start_def_id = tcx.require_lang_item(LangItem::Start, None);
                 let start_instance = Instance::expect_resolve(
                     tcx,
@@ -150,10 +149,6 @@ pub(crate) fn maybe_create_entry_wrapper(
                 let call_inst =
                     bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv, arg_sigpipe]);
                 bcx.inst_results(call_inst)[0]
-            } else {
-                // using user-defined start fn
-                let call_inst = bcx.ins().call(main_func_ref, &[arg_argc, arg_argv]);
-                bcx.inst_results(call_inst)[0]
             };
 
             bcx.ins().return_(&[result]);
diff --git a/compiler/rustc_codegen_gcc/build_system/src/test.rs b/compiler/rustc_codegen_gcc/build_system/src/test.rs
index 7cc7336612c..0e790a4befc 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/test.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/test.rs
@@ -426,19 +426,6 @@ fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> {
     run_command_with_env(&command, None, Some(env))?;
     maybe_run_command_in_vm(&[&cargo_target_dir.join("track-caller-attribute")], env, args)?;
 
-    // FIXME: create a function "display_if_not_quiet" or something along the line.
-    println!("[AOT] mod_bench");
-    let mut command = args.config_info.rustc_command_vec();
-    command.extend_from_slice(&[
-        &"example/mod_bench.rs",
-        &"--crate-type",
-        &"bin",
-        &"--target",
-        &args.config_info.target_triple,
-    ]);
-    run_command_with_env(&command, None, Some(env))?;
-    // FIXME: the compiled binary is not run.
-
     Ok(())
 }
 
@@ -696,19 +683,6 @@ fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> {
     Ok(())
 }
 
-// echo "[BENCH COMPILE] mod_bench"
-//
-// COMPILE_MOD_BENCH_INLINE="$RUSTC example/mod_bench.rs --crate-type bin -Zmir-opt-level=3 -O --crate-name mod_bench_inline"
-// COMPILE_MOD_BENCH_LLVM_0="rustc example/mod_bench.rs --crate-type bin -Copt-level=0 -o $cargo_target_dir/mod_bench_llvm_0 -Cpanic=abort"
-// COMPILE_MOD_BENCH_LLVM_1="rustc example/mod_bench.rs --crate-type bin -Copt-level=1 -o $cargo_target_dir/mod_bench_llvm_1 -Cpanic=abort"
-// COMPILE_MOD_BENCH_LLVM_2="rustc example/mod_bench.rs --crate-type bin -Copt-level=2 -o $cargo_target_dir/mod_bench_llvm_2 -Cpanic=abort"
-// COMPILE_MOD_BENCH_LLVM_3="rustc example/mod_bench.rs --crate-type bin -Copt-level=3 -o $cargo_target_dir/mod_bench_llvm_3 -Cpanic=abort"
-//
-// Use 100 runs, because a single compilations doesn't take more than ~150ms, so it isn't very slow
-// hyperfine --runs ${COMPILE_RUNS:-100} "$COMPILE_MOD_BENCH_INLINE" "$COMPILE_MOD_BENCH_LLVM_0" "$COMPILE_MOD_BENCH_LLVM_1" "$COMPILE_MOD_BENCH_LLVM_2" "$COMPILE_MOD_BENCH_LLVM_3"
-// echo "[BENCH RUN] mod_bench"
-// hyperfine --runs ${RUN_RUNS:-10} $cargo_target_dir/mod_bench{,_inline} $cargo_target_dir/mod_bench_llvm_*
-
 fn extended_rand_tests(env: &Env, args: &TestArg) -> Result<(), String> {
     if !args.is_using_gcc_master_branch() {
         println!("Not using GCC master branch. Skipping `extended_rand_tests`.");
diff --git a/compiler/rustc_codegen_gcc/example/alloc_example.rs b/compiler/rustc_codegen_gcc/example/alloc_example.rs
index 6ed8b9157f2..9a0b46d5b22 100644
--- a/compiler/rustc_codegen_gcc/example/alloc_example.rs
+++ b/compiler/rustc_codegen_gcc/example/alloc_example.rs
@@ -1,5 +1,6 @@
-#![feature(start, core_intrinsics, alloc_error_handler, lang_items)]
+#![feature(core_intrinsics, alloc_error_handler, lang_items)]
 #![no_std]
+#![no_main]
 #![allow(internal_features)]
 
 extern crate alloc;
@@ -37,8 +38,8 @@ unsafe extern "C" fn _Unwind_Resume() {
     core::intrinsics::unreachable();
 }
 
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int {
     let world: Box<&str> = Box::new("Hello World!\0");
     unsafe {
         puts(*world as *const str as *const u8);
diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
index 1d51e0a1856..4cbe66c5e4c 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
@@ -1,7 +1,7 @@
 // Adapted from https://github.com/sunfishcode/mir2cranelift/blob/master/rust-examples/nocore-hello-world.rs
 
 #![feature(
-    no_core, unboxed_closures, start, lang_items, never_type, linkage,
+    no_core, unboxed_closures, lang_items, never_type, linkage,
     extern_types, thread_local
 )]
 #![no_core]
diff --git a/compiler/rustc_codegen_gcc/example/mod_bench.rs b/compiler/rustc_codegen_gcc/example/mod_bench.rs
deleted file mode 100644
index e8a9cade747..00000000000
--- a/compiler/rustc_codegen_gcc/example/mod_bench.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-#![feature(start, core_intrinsics, lang_items)]
-#![no_std]
-#![allow(internal_features)]
-
-#[link(name = "c")]
-extern "C" {}
-
-#[panic_handler]
-fn panic_handler(_: &core::panic::PanicInfo<'_>) -> ! {
-    core::intrinsics::abort();
-}
-
-#[lang="eh_personality"]
-fn eh_personality(){}
-
-// Required for rustc_codegen_llvm
-#[no_mangle]
-unsafe extern "C" fn _Unwind_Resume() {
-    core::intrinsics::unreachable();
-}
-
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
-    for i in 2..100_000_000 {
-        black_box((i + 1) % i);
-    }
-
-    0
-}
-
-#[inline(never)]
-fn black_box(i: u32) {
-    if i != 1 {
-        core::intrinsics::abort();
-    }
-}
diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
index f43743fc2a4..bd5d6ba387c 100644
--- a/compiler/rustc_codegen_gcc/src/common.rs
+++ b/compiler/rustc_codegen_gcc/src/common.rs
@@ -64,6 +64,11 @@ impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         if type_is_pointer(typ) { self.context.new_null(typ) } else { self.const_int(typ, 0) }
     }
 
+    fn is_undef(&self, _val: RValue<'gcc>) -> bool {
+        // FIXME: actually check for undef
+        false
+    }
+
     fn const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc> {
         let local = self.current_func.borrow().expect("func").new_local(None, typ, "undefined");
         if typ.is_struct().is_some() {
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index c81c53359fd..30732c74eb3 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -513,7 +513,6 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         } else {
             // If the symbol already exists, it is an error: for example, the user wrote
             // #[no_mangle] extern "C" fn main(..) {..}
-            // instead of #[start]
             None
         }
     }
diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs
index d3aeb7f3bde..4b84b1dbfd3 100644
--- a/compiler/rustc_codegen_gcc/src/debuginfo.rs
+++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs
@@ -113,15 +113,15 @@ fn make_mir_scope<'gcc, 'tcx>(
     let scope_data = &mir.source_scopes[scope];
     let parent_scope = if let Some(parent) = scope_data.parent_scope {
         make_mir_scope(cx, _instance, mir, variables, debug_context, instantiated, parent);
-        debug_context.scopes[parent].unwrap()
+        debug_context.scopes[parent]
     } else {
         // The root is the function itself.
         let file = cx.sess().source_map().lookup_source_file(mir.span.lo());
-        debug_context.scopes[scope] = Some(DebugScope {
+        debug_context.scopes[scope] = DebugScope {
             file_start_pos: file.start_pos,
             file_end_pos: file.end_position(),
-            ..debug_context.scopes[scope].unwrap()
-        });
+            ..debug_context.scopes[scope]
+        };
         instantiated.insert(scope);
         return;
     };
@@ -130,7 +130,7 @@ fn make_mir_scope<'gcc, 'tcx>(
         if !vars.contains(scope) && scope_data.inlined.is_none() {
             // Do not create a DIScope if there are no variables defined in this
             // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat.
-            debug_context.scopes[scope] = Some(parent_scope);
+            debug_context.scopes[scope] = parent_scope;
             instantiated.insert(scope);
             return;
         }
@@ -157,12 +157,12 @@ fn make_mir_scope<'gcc, 'tcx>(
     // TODO(tempdragon): dbg_scope: Add support for scope extension here.
     inlined_at.or(p_inlined_at);
 
-    debug_context.scopes[scope] = Some(DebugScope {
+    debug_context.scopes[scope] = DebugScope {
         dbg_scope,
         inlined_at,
         file_start_pos: loc.file.start_pos,
         file_end_pos: loc.file.end_position(),
-    });
+    };
     instantiated.insert(scope);
 }
 
@@ -232,12 +232,12 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         }
 
         // Initialize fn debug context (including scopes).
-        let empty_scope = Some(DebugScope {
+        let empty_scope = DebugScope {
             dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)),
             inlined_at: None,
             file_start_pos: BytePos(0),
             file_end_pos: BytePos(0),
-        });
+        };
         let mut fn_debug_context = FunctionDebugContext {
             scopes: IndexVec::from_elem(empty_scope, mir.source_scopes.as_slice()),
             inlined_function_scopes: Default::default(),
diff --git a/compiler/rustc_codegen_gcc/tests/run/abort1.rs b/compiler/rustc_codegen_gcc/tests/run/abort1.rs
index 696197d7377..385e41a6881 100644
--- a/compiler/rustc_codegen_gcc/tests/run/abort1.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/abort1.rs
@@ -3,11 +3,12 @@
 // Run-time:
 //   status: signal
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
+#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -49,7 +50,7 @@ fn test_fail() -> ! {
     unsafe { intrinsics::abort() };
 }
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     test_fail();
 }
diff --git a/compiler/rustc_codegen_gcc/tests/run/abort2.rs b/compiler/rustc_codegen_gcc/tests/run/abort2.rs
index 714cd6c0f38..6c66a930e07 100644
--- a/compiler/rustc_codegen_gcc/tests/run/abort2.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/abort2.rs
@@ -3,11 +3,12 @@
 // Run-time:
 //   status: signal
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
+#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -50,8 +51,8 @@ fn fail() -> i32 {
     0
 }
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     fail();
     0
 }
diff --git a/compiler/rustc_codegen_gcc/tests/run/array.rs b/compiler/rustc_codegen_gcc/tests/run/array.rs
index c3c08c29c6d..e18a4ced6bc 100644
--- a/compiler/rustc_codegen_gcc/tests/run/array.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/array.rs
@@ -7,10 +7,11 @@
 //     5
 //     10
 
-#![feature(no_core, start)]
+#![feature(no_core)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 extern crate mini_core;
 
@@ -28,8 +29,8 @@ fn make_array() -> [u8; 3] {
     [42, 10, 5]
 }
 
-#[start]
-fn main(argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     let array = [42, 7, 5];
     let array2 = make_array();
     unsafe {
diff --git a/compiler/rustc_codegen_gcc/tests/run/assign.rs b/compiler/rustc_codegen_gcc/tests/run/assign.rs
index 2a47f0c2966..4d414c577a6 100644
--- a/compiler/rustc_codegen_gcc/tests/run/assign.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/assign.rs
@@ -6,10 +6,11 @@
 //     10
 
 #![allow(internal_features, unused_attributes)]
-#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs, track_caller)]
+#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs, track_caller)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -142,8 +143,8 @@ fn inc(num: isize) -> isize {
 }
 
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     argc = inc(argc);
     unsafe {
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc);
diff --git a/compiler/rustc_codegen_gcc/tests/run/closure.rs b/compiler/rustc_codegen_gcc/tests/run/closure.rs
index 46c47bc54ed..c7a236f74f9 100644
--- a/compiler/rustc_codegen_gcc/tests/run/closure.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/closure.rs
@@ -8,10 +8,11 @@
 //     Int argument: 2
 //     Both args: 11
 
-#![feature(no_core, start)]
+#![feature(no_core)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 extern crate mini_core;
 
@@ -22,8 +23,8 @@ mod libc {
     }
 }
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     let string = "Arg: %d\n\0";
     let mut closure = || {
         unsafe {
diff --git a/compiler/rustc_codegen_gcc/tests/run/condition.rs b/compiler/rustc_codegen_gcc/tests/run/condition.rs
index 039ef94eaa7..b02359702ed 100644
--- a/compiler/rustc_codegen_gcc/tests/run/condition.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/condition.rs
@@ -5,10 +5,11 @@
 //   stdout: true
 //     1
 
-#![feature(no_core, start)]
+#![feature(no_core)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 extern crate mini_core;
 
@@ -19,8 +20,8 @@ mod libc {
     }
 }
 
-#[start]
-fn main(argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     unsafe {
         if argc == 1 {
             libc::printf(b"true\n\0" as *const u8 as *const i8);
diff --git a/compiler/rustc_codegen_gcc/tests/run/empty_main.rs b/compiler/rustc_codegen_gcc/tests/run/empty_main.rs
index e66a859ad69..042e44080c5 100644
--- a/compiler/rustc_codegen_gcc/tests/run/empty_main.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/empty_main.rs
@@ -3,11 +3,12 @@
 // Run-time:
 //   status: 0
 
-#![feature(auto_traits, lang_items, no_core, start)]
+#![feature(auto_traits, lang_items, no_core)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -34,7 +35,7 @@ pub(crate) unsafe auto trait Freeze {}
  * Code
  */
 
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     0
 }
diff --git a/compiler/rustc_codegen_gcc/tests/run/exit.rs b/compiler/rustc_codegen_gcc/tests/run/exit.rs
index bf1cbeef302..9a7c91c0adb 100644
--- a/compiler/rustc_codegen_gcc/tests/run/exit.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/exit.rs
@@ -3,11 +3,12 @@
 // Run-time:
 //   status: 2
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+#![feature(auto_traits, lang_items, no_core, intrinsics)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 mod libc {
     #[link(name = "c")]
@@ -41,8 +42,8 @@ pub(crate) unsafe auto trait Freeze {}
  * Code
  */
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     unsafe {
         libc::exit(2);
     }
diff --git a/compiler/rustc_codegen_gcc/tests/run/exit_code.rs b/compiler/rustc_codegen_gcc/tests/run/exit_code.rs
index be7a233efda..c50d2b0d710 100644
--- a/compiler/rustc_codegen_gcc/tests/run/exit_code.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/exit_code.rs
@@ -3,11 +3,12 @@
 // Run-time:
 //   status: 1
 
-#![feature(auto_traits, lang_items, no_core, start)]
+#![feature(auto_traits, lang_items, no_core)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -34,7 +35,7 @@ pub(crate) unsafe auto trait Freeze {}
  * Code
  */
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     1
 }
diff --git a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs
index ed1bf72bb27..98b351e5044 100644
--- a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs
@@ -4,10 +4,11 @@
 //   status: 0
 //   stdout: 1
 
-#![feature(no_core, start)]
+#![feature(no_core)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 extern crate mini_core;
 
@@ -26,8 +27,8 @@ fn call_func(func: fn(i16) -> i8, param: i16) -> i8 {
     func(param)
 }
 
-#[start]
-fn main(argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     unsafe {
         let result = call_func(i16_as_i8, argc as i16) as isize;
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, result);
diff --git a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs
index 3ae79338216..9be64f991ee 100644
--- a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs
@@ -8,10 +8,11 @@
 //     11
 
 #![allow(internal_features, unused_attributes)]
-#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs, track_caller)]
+#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs, track_caller)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -148,8 +149,8 @@ fn update_num(num: &mut isize) {
     *num = *num + 5;
 }
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     let mut test = test(argc);
     unsafe {
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.field);
diff --git a/compiler/rustc_codegen_gcc/tests/run/operations.rs b/compiler/rustc_codegen_gcc/tests/run/operations.rs
index 0e44fc580b8..c92d3cc0b8f 100644
--- a/compiler/rustc_codegen_gcc/tests/run/operations.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/operations.rs
@@ -6,10 +6,11 @@
 //     10
 
 #![allow(internal_features, unused_attributes)]
-#![feature(auto_traits, lang_items, no_core, start, intrinsics, arbitrary_self_types, rustc_attrs)]
+#![feature(auto_traits, lang_items, no_core, intrinsics, arbitrary_self_types, rustc_attrs)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -231,8 +232,8 @@ pub fn panic_const_mul_overflow() -> ! {
  * Code
  */
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     unsafe {
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, 40 + argc);
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, 40 - argc);
diff --git a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs
index 2b8812ad51c..0ba49e7187f 100644
--- a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs
@@ -4,10 +4,11 @@
 //   status: 0
 //   stdout: 1
 
-#![feature(no_core, start)]
+#![feature(no_core)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 extern crate mini_core;
 
@@ -24,8 +25,8 @@ fn make_array() -> [u8; 3] {
     [42, 10, 5]
 }
 
-#[start]
-fn main(argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     unsafe {
         let ptr = ONE as *mut usize;
         let value = ptr as usize;
diff --git a/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs b/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs
index f2a5a2e4384..3cc1e274001 100644
--- a/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs
@@ -6,11 +6,12 @@
 //     10
 //     42
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+#![feature(auto_traits, lang_items, no_core, intrinsics)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 #[lang = "copy"]
 pub unsafe trait Copy {}
@@ -61,8 +62,8 @@ fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u3
     )
 }
 
-#[start]
-fn main(argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     let (a, b, c, d, e, f, g, h, i, j) = int_cast(10, 42);
     unsafe {
         libc::printf(b"%d\n\0" as *const u8 as *const i8, c);
diff --git a/compiler/rustc_codegen_gcc/tests/run/slice.rs b/compiler/rustc_codegen_gcc/tests/run/slice.rs
index fba93fc1554..825fcb8a081 100644
--- a/compiler/rustc_codegen_gcc/tests/run/slice.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/slice.rs
@@ -4,10 +4,11 @@
 //   status: 0
 //   stdout: 5
 
-#![feature(no_core, start)]
+#![feature(no_core)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 extern crate mini_core;
 
@@ -26,8 +27,8 @@ fn index_slice(s: &[u32]) -> u32 {
     }
 }
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     let array = [42, 7, 5];
     unsafe {
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, index_slice(&array));
diff --git a/compiler/rustc_codegen_gcc/tests/run/static.rs b/compiler/rustc_codegen_gcc/tests/run/static.rs
index a17ea2a4893..80c8782c4b1 100644
--- a/compiler/rustc_codegen_gcc/tests/run/static.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/static.rs
@@ -9,11 +9,12 @@
 //      12
 //      1
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
+#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -98,8 +99,8 @@ static mut WITH_REF: WithRef = WithRef {
     refe: unsafe { &TEST },
 };
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     unsafe {
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, CONSTANT);
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, TEST2.field);
diff --git a/compiler/rustc_codegen_gcc/tests/run/structs.rs b/compiler/rustc_codegen_gcc/tests/run/structs.rs
index d6455667400..59b8f358863 100644
--- a/compiler/rustc_codegen_gcc/tests/run/structs.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/structs.rs
@@ -5,11 +5,12 @@
 //   stdout: 1
 //     2
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+#![feature(auto_traits, lang_items, no_core, intrinsics)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -55,8 +56,8 @@ fn one() -> isize {
     1
 }
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     let test = Test {
         field: one(),
     };
diff --git a/compiler/rustc_codegen_gcc/tests/run/tuple.rs b/compiler/rustc_codegen_gcc/tests/run/tuple.rs
index 8a7d85ae867..ed60a56a68c 100644
--- a/compiler/rustc_codegen_gcc/tests/run/tuple.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/tuple.rs
@@ -4,11 +4,12 @@
 //   status: 0
 //   stdout: 3
 
-#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+#![feature(auto_traits, lang_items, no_core, intrinsics)]
 #![allow(internal_features)]
 
 #![no_std]
 #![no_core]
+#![no_main]
 
 /*
  * Core
@@ -42,8 +43,8 @@ mod libc {
  * Code
  */
 
-#[start]
-fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
     let test: (isize, isize, isize) = (3, 1, 4);
     unsafe {
         libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.0);
diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml
index c44d1a5e5c2..94f21ac5f57 100644
--- a/compiler/rustc_codegen_llvm/Cargo.toml
+++ b/compiler/rustc_codegen_llvm/Cargo.toml
@@ -9,6 +9,8 @@ test = false
 [dependencies]
 # tidy-alphabetical-start
 bitflags = "2.4.1"
+# To avoid duplicate dependencies, this should match the version of gimli used
+# by `rustc_codegen_ssa` via its `thorin-dwp` dependency.
 gimli = "0.30"
 itertools = "0.12"
 libc = "0.2"
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 509b24dd703..4706744f353 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -769,12 +769,9 @@ pub(crate) unsafe fn codegen(
             }
         }
 
-        // Two things to note:
-        // - If object files are just LLVM bitcode we write bitcode, copy it to
-        //   the .o file, and delete the bitcode if it wasn't otherwise
-        //   requested.
-        // - If we don't have the integrated assembler then we need to emit
-        //   asm from LLVM and use `gcc` to create the object file.
+        // Note that if object files are just LLVM bitcode we write bitcode,
+        // copy it to the .o file, and delete the bitcode if it wasn't
+        // otherwise requested.
 
         let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
         let bc_summary_out =
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index adfe8aeb5c5..b4e9b9f44f4 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -126,6 +126,10 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         unsafe { llvm::LLVMGetUndef(t) }
     }
 
+    fn is_undef(&self, v: &'ll Value) -> bool {
+        unsafe { llvm::LLVMIsUndef(v) == True }
+    }
+
     fn const_poison(&self, t: &'ll Type) -> &'ll Value {
         unsafe { llvm::LLVMGetPoison(t) }
     }
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 65345751842..91283a5944e 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -751,7 +751,6 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         } else {
             // If the symbol already exists, it is an error: for example, the user wrote
             // #[no_mangle] extern "C" fn main(..) {..}
-            // instead of #[start]
             None
         }
     }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
index e545ce386ed..11eb9651af6 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
@@ -9,7 +9,7 @@ use rustc_middle::mir::{Body, SourceScope};
 use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv};
 use rustc_middle::ty::{self, Instance};
 use rustc_session::config::DebugInfo;
-use rustc_span::{BytePos, hygiene};
+use rustc_span::{BytePos, DUMMY_SP, hygiene};
 
 use super::metadata::file_metadata;
 use super::utils::DIB;
@@ -85,23 +85,15 @@ fn make_mir_scope<'ll, 'tcx>(
             discriminators,
             parent,
         );
-        if let Some(parent_scope) = debug_context.scopes[parent] {
-            parent_scope
-        } else {
-            // If the parent scope could not be represented then no children
-            // can be either.
-            debug_context.scopes[scope] = None;
-            instantiated.insert(scope);
-            return;
-        }
+        debug_context.scopes[parent]
     } else {
         // The root is the function itself.
         let file = cx.sess().source_map().lookup_source_file(mir.span.lo());
-        debug_context.scopes[scope] = Some(DebugScope {
+        debug_context.scopes[scope] = DebugScope {
             file_start_pos: file.start_pos,
             file_end_pos: file.end_position(),
-            ..debug_context.scopes[scope].unwrap()
-        });
+            ..debug_context.scopes[scope]
+        };
         instantiated.insert(scope);
         return;
     };
@@ -112,7 +104,7 @@ fn make_mir_scope<'ll, 'tcx>(
     {
         // Do not create a DIScope if there are no variables defined in this
         // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat.
-        debug_context.scopes[scope] = Some(parent_scope);
+        debug_context.scopes[scope] = parent_scope;
         instantiated.insert(scope);
         return;
     }
@@ -145,14 +137,7 @@ fn make_mir_scope<'ll, 'tcx>(
         },
     };
 
-    let mut debug_scope = Some(DebugScope {
-        dbg_scope,
-        inlined_at: parent_scope.inlined_at,
-        file_start_pos: loc.file.start_pos,
-        file_end_pos: loc.file.end_position(),
-    });
-
-    if let Some((_, callsite_span)) = scope_data.inlined {
+    let inlined_at = scope_data.inlined.map(|(_, callsite_span)| {
         let callsite_span = hygiene::walk_chain_collapsed(callsite_span, mir.span);
         let callsite_scope = parent_scope.adjust_dbg_scope_for_span(cx, callsite_span);
         let loc = cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span);
@@ -175,29 +160,29 @@ fn make_mir_scope<'ll, 'tcx>(
         // Note further that we can't key this hashtable on the span itself,
         // because these spans could have distinct SyntaxContexts. We have
         // to key on exactly what we're giving to LLVM.
-        let inlined_at = match discriminators.entry(callsite_span.lo()) {
+        match discriminators.entry(callsite_span.lo()) {
             Entry::Occupied(mut o) => {
                 *o.get_mut() += 1;
+                // NB: We have to emit *something* here or we'll fail LLVM IR verification
+                // in at least some circumstances (see issue #135322) so if the required
+                // discriminant cannot be encoded fall back to the dummy location.
                 unsafe { llvm::LLVMRustDILocationCloneWithBaseDiscriminator(loc, *o.get()) }
+                    .unwrap_or_else(|| {
+                        cx.dbg_loc(callsite_scope, parent_scope.inlined_at, DUMMY_SP)
+                    })
             }
             Entry::Vacant(v) => {
                 v.insert(0);
-                Some(loc)
-            }
-        };
-        match inlined_at {
-            Some(inlined_at) => {
-                debug_scope.as_mut().unwrap().inlined_at = Some(inlined_at);
-            }
-            None => {
-                // LLVM has a maximum discriminator that it can encode (currently
-                // it uses 12 bits for 4096 possible values). If we exceed that
-                // there is little we can do but drop the debug info.
-                debug_scope = None;
+                loc
             }
         }
-    }
+    });
 
-    debug_context.scopes[scope] = debug_scope;
+    debug_context.scopes[scope] = DebugScope {
+        dbg_scope,
+        inlined_at: inlined_at.or(parent_scope.inlined_at),
+        file_start_pos: loc.file.start_pos,
+        file_end_pos: loc.file.end_position(),
+    };
     instantiated.insert(scope);
 }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 88e43e1c678..8d782a618fc 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -442,7 +442,7 @@ pub(crate) fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) ->
         // (or if there is no allocator argument).
         ty::Adt(def, args)
             if def.is_box()
-                && args.get(1).map_or(true, |arg| cx.layout_of(arg.expect_ty()).is_1zst()) =>
+                && args.get(1).is_none_or(|arg| cx.layout_of(arg.expect_ty()).is_1zst()) =>
         {
             build_pointer_or_reference_di_node(cx, t, t.expect_boxed_ty(), unique_type_id)
         }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 755f4816acf..e6778411365 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -295,12 +295,12 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         }
 
         // Initialize fn debug context (including scopes).
-        let empty_scope = Some(DebugScope {
+        let empty_scope = DebugScope {
             dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)),
             inlined_at: None,
             file_start_pos: BytePos(0),
             file_end_pos: BytePos(0),
-        });
+        };
         let mut fn_debug_context = FunctionDebugContext {
             scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes),
             inlined_function_scopes: Default::default(),
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index ec6c84f6f25..009d15a932f 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -741,8 +741,11 @@ pub mod debuginfo {
     pub type DIEnumerator = DIDescriptor;
     pub type DITemplateTypeParameter = DIDescriptor;
 
-    // These values **must** match with LLVMRustDIFlags!!
     bitflags! {
+        /// Must match the layout of `LLVMDIFlags` in the LLVM-C API.
+        ///
+        /// Each value declared here must also be covered by the static
+        /// assertions in `RustWrapper.cpp` used by `fromRust(LLVMDIFlags)`.
         #[repr(transparent)]
         #[derive(Clone, Copy, Default)]
         pub struct DIFlags: u32 {
@@ -752,7 +755,7 @@ pub mod debuginfo {
             const FlagPublic              = 3;
             const FlagFwdDecl             = (1 << 2);
             const FlagAppleBlock          = (1 << 3);
-            const FlagBlockByrefStruct    = (1 << 4);
+            const FlagReservedBit4        = (1 << 4);
             const FlagVirtual             = (1 << 5);
             const FlagArtificial          = (1 << 6);
             const FlagExplicit            = (1 << 7);
@@ -763,10 +766,21 @@ pub mod debuginfo {
             const FlagStaticMember        = (1 << 12);
             const FlagLValueReference     = (1 << 13);
             const FlagRValueReference     = (1 << 14);
-            const FlagExternalTypeRef     = (1 << 15);
+            const FlagReserved            = (1 << 15);
+            const FlagSingleInheritance   = (1 << 16);
+            const FlagMultipleInheritance = (2 << 16);
+            const FlagVirtualInheritance  = (3 << 16);
             const FlagIntroducedVirtual   = (1 << 18);
             const FlagBitField            = (1 << 19);
             const FlagNoReturn            = (1 << 20);
+            // The bit at (1 << 21) is unused, but was `LLVMDIFlagMainSubprogram`.
+            const FlagTypePassByValue     = (1 << 22);
+            const FlagTypePassByReference = (1 << 23);
+            const FlagEnumClass           = (1 << 24);
+            const FlagThunk               = (1 << 25);
+            const FlagNonTrivial          = (1 << 26);
+            const FlagBigEndian           = (1 << 27);
+            const FlagLittleEndian        = (1 << 28);
         }
     }
 
@@ -918,6 +932,7 @@ unsafe extern "C" {
     pub fn LLVMMetadataTypeInContext(C: &Context) -> &Type;
 
     // Operations on all values
+    pub fn LLVMIsUndef(Val: &Value) -> Bool;
     pub fn LLVMTypeOf(Val: &Value) -> &Type;
     pub fn LLVMGetValueName2(Val: &Value, Length: *mut size_t) -> *const c_char;
     pub fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t);
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index 3254b5d38e7..b6b453d069e 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -59,5 +59,5 @@ default-features = false
 features = ["read_core", "elf", "macho", "pe", "xcoff", "unaligned", "archive", "write", "wasm"]
 
 [target.'cfg(windows)'.dependencies.windows]
-version = "0.57.0"
+version = "0.59.0"
 features = ["Win32_Globalization"]
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index 484f467068a..a4c50dcc135 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -211,7 +211,7 @@ 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_main_functions = entry symbol `main` declared multiple times
-    .help = did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead
+    .help = did you use `#[no_mangle]` on `fn main`? Use `#![no_main]` to suppress the usual Rust-generated entry point
 
 codegen_ssa_no_field = no field `{$name}`
 
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 544578b29f1..83724af604d 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -490,8 +490,8 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         let ptr_ty = cx.type_ptr();
         let (arg_argc, arg_argv) = get_argc_argv(&mut bx);
 
-        let (start_fn, start_ty, args, instance) = if let EntryFnType::Main { sigpipe } = entry_type
-        {
+        let EntryFnType::Main { sigpipe } = entry_type;
+        let (start_fn, start_ty, args, instance) = {
             let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None);
             let start_instance = ty::Instance::expect_resolve(
                 cx.tcx(),
@@ -512,10 +512,6 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                 vec![rust_main, arg_argc, arg_argv, arg_sigpipe],
                 Some(start_instance),
             )
-        } else {
-            debug!("using user-defined start fn");
-            let start_ty = cx.type_func(&[isize_ty, ptr_ty], isize_ty);
-            (rust_main, start_ty, vec![arg_argc, arg_argv], None)
         };
 
         let result = bx.call(start_ty, None, None, start_fn, &args, None, instance);
@@ -530,7 +526,8 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     }
 }
 
-/// Obtain the `argc` and `argv` values to pass to the rust start function.
+/// Obtain the `argc` and `argv` values to pass to the rust start function
+/// (i.e., the "start" lang item).
 fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(bx: &mut Bx) -> (Bx::Value, Bx::Value) {
     if bx.cx().sess().target.os.contains("uefi") {
         // Params for UEFI
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index 843a996d2bf..5924c8991ad 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -19,9 +19,7 @@ use crate::traits::*;
 
 pub struct FunctionDebugContext<'tcx, S, L> {
     /// Maps from source code to the corresponding debug info scope.
-    /// May be None if the backend is not capable of representing the scope for
-    /// some reason.
-    pub scopes: IndexVec<mir::SourceScope, Option<DebugScope<S, L>>>,
+    pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>,
 
     /// Maps from an inlined function to its debug info declaration.
     pub inlined_function_scopes: FxHashMap<Instance<'tcx>, S>,
@@ -232,7 +230,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         &self,
         source_info: mir::SourceInfo,
     ) -> Option<(Bx::DIScope, Option<Bx::DILocation>, Span)> {
-        let scope = &self.debug_context.as_ref()?.scopes[source_info.scope]?;
+        let scope = &self.debug_context.as_ref()?.scopes[source_info.scope];
         let span = hygiene::walk_chain_collapsed(source_info.span, self.mir.span);
         Some((scope.adjust_dbg_scope_for_span(self.cx, span), scope.inlined_at, span))
     }
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 19101ec2d1b..9ca7d4f8f00 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -204,14 +204,30 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
         let alloc_align = alloc.inner().align;
         assert!(alloc_align >= layout.align.abi);
 
+        // Returns `None` when the value is partially undefined or any byte of it has provenance.
+        // Otherwise returns the value or (if the entire value is undef) returns an undef.
         let read_scalar = |start, size, s: abi::Scalar, ty| {
+            let range = alloc_range(start, size);
             match alloc.0.read_scalar(
                 bx,
-                alloc_range(start, size),
+                range,
                 /*read_provenance*/ matches!(s.primitive(), abi::Primitive::Pointer(_)),
             ) {
-                Ok(val) => bx.scalar_to_backend(val, s, ty),
-                Err(_) => bx.const_poison(ty),
+                Ok(val) => Some(bx.scalar_to_backend(val, s, ty)),
+                Err(_) => {
+                    // We may have failed due to partial provenance or unexpected provenance,
+                    // continue down the normal code path if so.
+                    if alloc.0.provenance().range_empty(range, &bx.tcx())
+                        // Since `read_scalar` failed, but there were no relocations involved, the
+                        // bytes must be partially or fully uninitialized. Thus we can now unwrap the
+                        // information about the range of uninit bytes and check if it's the full range.
+                        && alloc.0.init_mask().is_range_initialized(range).unwrap_err() == range
+                    {
+                        Some(bx.const_undef(ty))
+                    } else {
+                        None
+                    }
+                }
             }
         };
 
@@ -222,16 +238,14 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
         // check that walks over the type of `mplace` to make sure it is truly correct to treat this
         // like a `Scalar` (or `ScalarPair`).
         match layout.backend_repr {
-            BackendRepr::Scalar(s @ abi::Scalar::Initialized { .. }) => {
+            BackendRepr::Scalar(s) => {
                 let size = s.size(bx);
                 assert_eq!(size, layout.size, "abi::Scalar size does not match layout size");
-                let val = read_scalar(offset, size, s, bx.immediate_backend_type(layout));
-                OperandRef { val: OperandValue::Immediate(val), layout }
+                if let Some(val) = read_scalar(offset, size, s, bx.immediate_backend_type(layout)) {
+                    return OperandRef { val: OperandValue::Immediate(val), layout };
+                }
             }
-            BackendRepr::ScalarPair(
-                a @ abi::Scalar::Initialized { .. },
-                b @ abi::Scalar::Initialized { .. },
-            ) => {
+            BackendRepr::ScalarPair(a, b) => {
                 let (a_size, b_size) = (a.size(bx), b.size(bx));
                 let b_offset = (offset + a_size).align_to(b.align(bx).abi);
                 assert!(b_offset.bytes() > 0);
@@ -247,20 +261,21 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
                     b,
                     bx.scalar_pair_element_backend_type(layout, 1, true),
                 );
-                OperandRef { val: OperandValue::Pair(a_val, b_val), layout }
-            }
-            _ if layout.is_zst() => OperandRef::zero_sized(layout),
-            _ => {
-                // Neither a scalar nor scalar pair. Load from a place
-                // FIXME: should we cache `const_data_from_alloc` to avoid repeating this for the
-                // same `ConstAllocation`?
-                let init = bx.const_data_from_alloc(alloc);
-                let base_addr = bx.static_addr_of(init, alloc_align, None);
-
-                let llval = bx.const_ptr_byte_offset(base_addr, offset);
-                bx.load_operand(PlaceRef::new_sized(llval, layout))
+                if let (Some(a_val), Some(b_val)) = (a_val, b_val) {
+                    return OperandRef { val: OperandValue::Pair(a_val, b_val), layout };
+                }
             }
+            _ if layout.is_zst() => return OperandRef::zero_sized(layout),
+            _ => {}
         }
+        // Neither a scalar nor scalar pair. Load from a place
+        // FIXME: should we cache `const_data_from_alloc` to avoid repeating this for the
+        // same `ConstAllocation`?
+        let init = bx.const_data_from_alloc(alloc);
+        let base_addr = bx.static_addr_of(init, alloc_align, None);
+
+        let llval = bx.const_ptr_byte_offset(base_addr, offset);
+        bx.load_operand(PlaceRef::new_sized(llval, layout))
     }
 
     /// Asserts that this operand refers to a scalar and returns
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 31793641d75..e775d219c7b 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -8,11 +8,11 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_middle::{bug, mir, span_bug};
 use rustc_session::config::OptLevel;
 use rustc_span::{DUMMY_SP, Span};
-use tracing::{debug, instrument};
+use tracing::{debug, instrument, trace};
 
-use super::FunctionCx;
 use super::operand::{OperandRef, OperandValue};
 use super::place::PlaceRef;
+use super::{FunctionCx, LocalRef};
 use crate::common::IntPredicate;
 use crate::traits::*;
 use crate::{MemFlags, base};
@@ -93,6 +93,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     return;
                 }
 
+                // If `v` is an integer constant whose value is just a single byte repeated N times,
+                // emit a `memset` filling the entire `dest` with that byte.
                 let try_init_all_same = |bx: &mut Bx, v| {
                     let start = dest.val.llval;
                     let size = bx.const_usize(dest.layout.size.bytes());
@@ -117,13 +119,33 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     false
                 };
 
+                trace!(?cg_elem.val);
                 match cg_elem.val {
                     OperandValue::Immediate(v) => {
                         if try_init_all_same(bx, v) {
                             return;
                         }
                     }
-                    _ => (),
+                    OperandValue::Pair(a, b) => {
+                        let a_is_undef = bx.cx().is_undef(a);
+                        match (a_is_undef, bx.cx().is_undef(b)) {
+                            // Can happen for uninit unions
+                            (true, true) => {
+                                // FIXME: can we produce better output here?
+                            }
+                            (false, true) | (true, false) => {
+                                let val = if a_is_undef { b } else { a };
+                                if try_init_all_same(bx, val) {
+                                    return;
+                                }
+                            }
+                            (false, false) => {
+                                // FIXME: if both are the same value, use try_init_all_same
+                            }
+                        }
+                    }
+                    OperandValue::ZeroSized => unreachable!("checked above"),
+                    OperandValue::Ref(..) => {}
                 }
 
                 let count = self
@@ -365,10 +387,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         use abi::Primitive::*;
         imm = bx.from_immediate(imm);
 
-        // When scalars are passed by value, there's no metadata recording their
-        // valid ranges. For example, `char`s are passed as just `i32`, with no
-        // way for LLVM to know that they're 0x10FFFF at most. Thus we assume
-        // the range of the input value too, not just the output range.
+        // If we have a scalar, we must already know its range. Either
+        //
+        // 1) It's a parameter with `range` parameter metadata,
+        // 2) It's something we `load`ed with `!range` metadata, or
+        // 3) After a transmute we `assume`d the range (see below).
+        //
+        // That said, last time we tried removing this, it didn't actually help
+        // the rustc-perf results, so might as well keep doing it
+        // <https://github.com/rust-lang/rust/pull/135610#issuecomment-2599275182>
         self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
 
         imm = match (from_scalar.primitive(), to_scalar.primitive()) {
@@ -389,7 +416,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 bx.bitcast(int_imm, to_backend_ty)
             }
         };
+
+        // This `assume` remains important for cases like (a conceptual)
+        //    transmute::<u32, NonZeroU32>(x) == 0
+        // since it's never passed to something with parameter metadata (especially
+        // after MIR inlining) so the only way to tell the backend about the
+        // constraint that the `transmute` introduced is to `assume` it.
         self.assume_scalar_range(bx, imm, to_scalar, to_backend_ty);
+
         imm = bx.to_immediate_scalar(imm, to_scalar);
         imm
     }
@@ -411,31 +445,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             return;
         }
 
-        let abi::WrappingRange { start, end } = scalar.valid_range(self.cx);
-
-        if start <= end {
-            if start > 0 {
-                let low = bx.const_uint_big(backend_ty, start);
-                let cmp = bx.icmp(IntPredicate::IntUGE, imm, low);
-                bx.assume(cmp);
-            }
-
-            let type_max = scalar.size(self.cx).unsigned_int_max();
-            if end < type_max {
-                let high = bx.const_uint_big(backend_ty, end);
-                let cmp = bx.icmp(IntPredicate::IntULE, imm, high);
-                bx.assume(cmp);
-            }
-        } else {
-            let low = bx.const_uint_big(backend_ty, start);
-            let cmp_low = bx.icmp(IntPredicate::IntUGE, imm, low);
-
-            let high = bx.const_uint_big(backend_ty, end);
-            let cmp_high = bx.icmp(IntPredicate::IntULE, imm, high);
-
-            let or = bx.or(cmp_low, cmp_high);
-            bx.assume(or);
-        }
+        let range = scalar.valid_range(self.cx);
+        bx.assume_integer_range(imm, backend_ty, range);
     }
 
     pub(crate) fn codegen_rvalue_unsized(
@@ -607,6 +618,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 self.codegen_place_to_pointer(bx, place, mk_ptr)
             }
 
+            mir::Rvalue::Len(place) => {
+                let size = self.evaluate_array_len(bx, place);
+                OperandRef {
+                    val: OperandValue::Immediate(size),
+                    layout: bx.cx().layout_of(bx.tcx().types.usize),
+                }
+            }
+
             mir::Rvalue::BinaryOp(op_with_overflow, box (ref lhs, ref rhs))
                 if let Some(op) = op_with_overflow.overflowing_to_wrapping() =>
             {
@@ -806,6 +825,24 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         }
     }
 
+    fn evaluate_array_len(&mut self, bx: &mut Bx, place: mir::Place<'tcx>) -> Bx::Value {
+        // ZST are passed as operands and require special handling
+        // because codegen_place() panics if Local is operand.
+        if let Some(index) = place.as_local() {
+            if let LocalRef::Operand(op) = self.locals[index] {
+                if let ty::Array(_, n) = op.layout.ty.kind() {
+                    let n = n
+                        .try_to_target_usize(bx.tcx())
+                        .expect("expected monomorphic const in codegen");
+                    return bx.cx().const_usize(n);
+                }
+            }
+        }
+        // use common size calculation for non zero-sized types
+        let cg_value = self.codegen_place(bx, place.as_ref());
+        cg_value.len(bx.cx())
+    }
+
     /// Codegen an `Rvalue::RawPtr` or `Rvalue::Ref`
     fn codegen_place_to_pointer(
         &mut self,
@@ -1077,6 +1114,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             mir::Rvalue::Ref(..) |
             mir::Rvalue::CopyForDeref(..) |
             mir::Rvalue::RawPtr(..) |
+            mir::Rvalue::Len(..) |
             mir::Rvalue::Cast(..) | // (*)
             mir::Rvalue::ShallowInitBox(..) | // (*)
             mir::Rvalue::BinaryOp(..) |
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 3ee13b19f66..bbf87a59942 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -217,6 +217,27 @@ pub trait BuilderMethods<'a, 'tcx>:
         dest: PlaceRef<'tcx, Self::Value>,
     );
 
+    /// Emits an `assume` that the integer value `imm` of type `ty` is contained in `range`.
+    ///
+    /// This *always* emits the assumption, so you probably want to check the
+    /// optimization level and `Scalar::is_always_valid` before calling it.
+    fn assume_integer_range(&mut self, imm: Self::Value, ty: Self::Type, range: WrappingRange) {
+        let WrappingRange { start, end } = range;
+
+        // Perhaps one day we'll be able to use assume operand bundles for this,
+        // but for now this encoding with a single icmp+assume is best per
+        // <https://github.com/llvm/llvm-project/issues/123278#issuecomment-2597440158>
+        let shifted = if start == 0 {
+            imm
+        } else {
+            let low = self.const_uint_big(ty, start);
+            self.sub(imm, low)
+        };
+        let width = self.const_uint_big(ty, u128::wrapping_sub(end, start));
+        let cmp = self.icmp(IntPredicate::IntULE, shifted, width);
+        self.assume(cmp);
+    }
+
     fn range_metadata(&mut self, load: Self::Value, range: WrappingRange);
     fn nonnull_metadata(&mut self, load: Self::Value);
 
diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs
index 9af463a691a..d0de7ff0b5f 100644
--- a/compiler/rustc_codegen_ssa/src/traits/consts.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs
@@ -9,6 +9,7 @@ pub trait ConstCodegenMethods<'tcx>: BackendTypes {
     /// Generate an uninitialized value (matching uninitialized memory in MIR).
     /// Whether memory is initialized or not is tracked byte-for-byte.
     fn const_undef(&self, t: Self::Type) -> Self::Value;
+    fn is_undef(&self, v: Self::Value) -> bool;
     /// Generate a fake value. Poison always affects the entire value, even if just a single byte is
     /// poison. This can only be used in codepaths that are already UB, i.e., UB-free Rust code
     /// (including code that e.g. copies uninit memory with `MaybeUninit`) can never encounter a
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index 4861b7a4430..d4bfb781320 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -424,7 +424,7 @@ const_eval_unstable_in_stable_exposed =
     .bypass_sugg = otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
 
 const_eval_unstable_intrinsic = `{$name}` is not yet stable as a const intrinsic
-    .help = add `#![feature({$feature})]` to the crate attributes to enable
+const_eval_unstable_intrinsic_suggestion = add `#![feature({$feature})]` to the crate attributes to enable
 
 const_eval_unterminated_c_string =
     reading a null-terminated string starting at {$pointer} with no null found before end of allocation
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index 6c940124193..ed34996a7a7 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -464,6 +464,12 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
             err_span,
         );
     }
+
+    fn crate_inject_span(&self) -> Option<Span> {
+        self.tcx.hir_crate_items(()).definitions().next().and_then(|id| {
+            self.tcx.crate_level_attribute_injection_span(self.tcx.local_def_id_to_hir_id(id))
+        })
+    }
 }
 
 impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
@@ -495,7 +501,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
             Rvalue::Use(_)
             | Rvalue::CopyForDeref(..)
             | Rvalue::Repeat(..)
-            | Rvalue::Discriminant(..) => {}
+            | Rvalue::Discriminant(..)
+            | Rvalue::Len(_) => {}
 
             Rvalue::Aggregate(kind, ..) => {
                 if let AggregateKind::Coroutine(def_id, ..) = kind.as_ref()
@@ -579,27 +586,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
             ) => {}
             Rvalue::ShallowInitBox(_, _) => {}
 
-            Rvalue::UnaryOp(op, operand) => {
+            Rvalue::UnaryOp(_, operand) => {
                 let ty = operand.ty(self.body, self.tcx);
-                match op {
-                    UnOp::Not | UnOp::Neg => {
-                        if is_int_bool_float_or_char(ty) {
-                            // Int, bool, float, and char operations are fine.
-                        } else {
-                            span_bug!(
-                                self.span,
-                                "non-primitive type in `Rvalue::UnaryOp{op:?}`: {ty:?}",
-                            );
-                        }
-                    }
-                    UnOp::PtrMetadata => {
-                        if !ty.is_ref() && !ty.is_unsafe_ptr() {
-                            span_bug!(
-                                self.span,
-                                "non-pointer type in `Rvalue::UnaryOp({op:?})`: {ty:?}",
-                            );
-                        }
-                    }
+                if is_int_bool_float_or_char(ty) {
+                    // Int, bool, float, and char operations are fine.
+                } else {
+                    span_bug!(self.span, "non-primitive type in `Rvalue::UnaryOp`: {:?}", ty);
                 }
             }
 
@@ -823,6 +815,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                                 name: intrinsic.name,
                                 feature,
                                 const_stable_indirect: is_const_stable,
+                                suggestion: self.crate_inject_span(),
                             });
                         }
                         Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
@@ -911,7 +904,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                                 // regular stability.
                                 feature == sym::rustc_private
                                     && issue == NonZero::new(27812)
-                                    && self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked
+                                    && tcx.sess.opts.unstable_opts.force_unstable_if_unmarked
                             };
                         // Even if the feature is enabled, we still need check_op to double-check
                         // this if the callee is not safe to expose on stable.
@@ -921,6 +914,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                                 feature,
                                 feature_enabled,
                                 safe_to_expose_on_stable: callee_safe_to_expose_on_stable,
+                                suggestion_span: self.crate_inject_span(),
                             });
                         }
                     }
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index 7d103055a7c..3c83a7b92cd 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -1,8 +1,8 @@
 //! Concrete error types for all operations which may be invalid in a certain const context.
 
 use hir::{ConstContext, LangItem};
-use rustc_errors::Diag;
 use rustc_errors::codes::*;
+use rustc_errors::{Applicability, Diag};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::TyCtxtInferExt;
@@ -388,6 +388,7 @@ pub(crate) struct FnCallUnstable {
     /// expose on stable.
     pub feature_enabled: bool,
     pub safe_to_expose_on_stable: bool,
+    pub suggestion_span: Option<Span>,
 }
 
 impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
@@ -407,8 +408,18 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
             def_path: ccx.tcx.def_path_str(self.def_id),
         });
         // FIXME: make this translatable
+        let msg = format!("add `#![feature({})]` to the crate attributes to enable", self.feature);
         #[allow(rustc::untranslatable_diagnostic)]
-        err.help(format!("add `#![feature({})]` to the crate attributes to enable", self.feature));
+        if let Some(span) = self.suggestion_span {
+            err.span_suggestion_verbose(
+                span,
+                msg,
+                format!("#![feature({})]\n", self.feature),
+                Applicability::MachineApplicable,
+            );
+        } else {
+            err.help(msg);
+        }
 
         err
     }
@@ -436,6 +447,7 @@ pub(crate) struct IntrinsicUnstable {
     pub name: Symbol,
     pub feature: Symbol,
     pub const_stable_indirect: bool,
+    pub suggestion: Option<Span>,
 }
 
 impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable {
@@ -455,6 +467,8 @@ impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable {
             span,
             name: self.name,
             feature: self.feature,
+            suggestion: self.suggestion,
+            help: self.suggestion.is_none(),
         })
     }
 }
diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
index b1b7fb406b1..e244b50a4b5 100644
--- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
@@ -230,7 +230,9 @@ where
             Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx))
         }
 
-        Rvalue::Discriminant(place) => in_place::<Q, _>(cx, in_local, place.as_ref()),
+        Rvalue::Discriminant(place) | Rvalue::Len(place) => {
+            in_place::<Q, _>(cx, in_local, place.as_ref())
+        }
 
         Rvalue::CopyForDeref(place) => in_place::<Q, _>(cx, in_local, place.as_ref()),
 
diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs
index 5a6e7ab2bee..79df63a9e84 100644
--- a/compiler/rustc_const_eval/src/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs
@@ -197,6 +197,7 @@ where
             | mir::Rvalue::CopyForDeref(..)
             | mir::Rvalue::ThreadLocalRef(..)
             | mir::Rvalue::Repeat(..)
+            | mir::Rvalue::Len(..)
             | mir::Rvalue::BinaryOp(..)
             | mir::Rvalue::NullaryOp(..)
             | mir::Rvalue::UnaryOp(..)
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index 3fe78171cd9..1ee9214c4b2 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -123,12 +123,19 @@ pub(crate) struct UnstableConstFn {
 
 #[derive(Diagnostic)]
 #[diag(const_eval_unstable_intrinsic)]
-#[help]
 pub(crate) struct UnstableIntrinsic {
     #[primary_span]
     pub span: Span,
     pub name: Symbol,
     pub feature: Symbol,
+    #[suggestion(
+        const_eval_unstable_intrinsic_suggestion,
+        code = "#![feature({feature})]\n",
+        applicability = "machine-applicable"
+    )]
+    pub suggestion: Option<Span>,
+    #[help(const_eval_unstable_intrinsic_suggestion)]
+    pub help: bool,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 32e77fe1024..b61865be667 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -9,13 +9,12 @@ use rustc_middle::ty::layout::FnAbiOf;
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_middle::{bug, mir, span_bug};
 use rustc_span::source_map::Spanned;
-use rustc_span::{DesugaringKind, Span};
 use rustc_target::callconv::FnAbi;
 use tracing::{info, instrument, trace};
 
 use super::{
     FnArg, FnVal, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemPlaceMeta, PlaceTy,
-    Projectable, interp_ok, throw_ub,
+    Projectable, Scalar, interp_ok, throw_ub,
 };
 use crate::util;
 
@@ -81,9 +80,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         use rustc_middle::mir::StatementKind::*;
 
         match &stmt.kind {
-            Assign(box (place, rvalue)) => {
-                self.eval_rvalue_into_place(rvalue, *place, stmt.source_info.span)?
-            }
+            Assign(box (place, rvalue)) => self.eval_rvalue_into_place(rvalue, *place)?,
 
             SetDiscriminant { place, variant_index } => {
                 let dest = self.eval_place(**place)?;
@@ -162,7 +159,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         &mut self,
         rvalue: &mir::Rvalue<'tcx>,
         place: mir::Place<'tcx>,
-        span: Span,
     ) -> InterpResult<'tcx> {
         let dest = self.eval_place(place)?;
         // FIXME: ensure some kind of non-aliasing between LHS and RHS?
@@ -218,6 +214,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 self.write_repeat(operand, &dest)?;
             }
 
+            Len(place) => {
+                let src = self.eval_place(place)?;
+                let len = src.len(self)?;
+                self.write_scalar(Scalar::from_target_usize(len, self), &dest)?;
+            }
+
             Ref(_, borrow_kind, place) => {
                 let src = self.eval_place(place)?;
                 let place = self.force_allocation(&src)?;
@@ -248,13 +250,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 let src = self.eval_place(place)?;
                 let place = self.force_allocation(&src)?;
                 let mut val = ImmTy::from_immediate(place.to_ref(self), dest.layout);
-                if !place_base_raw
-                    && span.desugaring_kind() != Some(DesugaringKind::IndexBoundsCheckReborrow)
-                {
+                if !place_base_raw {
                     // If this was not already raw, it needs retagging.
-                    // As a special hack, we exclude the desugared `PtrMetadata(&raw const *_n)`
-                    // from indexing. (Really we should not do any retag on `&raw` but that does not
-                    // currently work with Stacked Borrows.)
                     val = M::retag_ptr_value(self, mir::RetagKind::Raw, &val)?;
                 }
                 self.write_immediate(*val, &dest)?;
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index c8ecddb046c..889a8299c18 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -32,7 +32,7 @@ tracing = "0.1"
 version = "0.12"
 
 [target.'cfg(windows)'.dependencies.windows]
-version = "0.57.0"
+version = "0.59.0"
 features = [
     "Win32_Foundation",
     "Win32_Storage_FileSystem",
diff --git a/compiler/rustc_data_structures/src/flock/windows.rs b/compiler/rustc_data_structures/src/flock/windows.rs
index 9739e501272..e761faee67b 100644
--- a/compiler/rustc_data_structures/src/flock/windows.rs
+++ b/compiler/rustc_data_structures/src/flock/windows.rs
@@ -60,9 +60,9 @@ impl Lock {
 
         unsafe {
             LockFileEx(
-                HANDLE(file.as_raw_handle() as isize),
+                HANDLE(file.as_raw_handle()),
                 flags,
-                0,
+                None,
                 u32::MAX,
                 u32::MAX,
                 &mut overlapped,
diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml
index 2f0fe64b096..07b88e59723 100644
--- a/compiler/rustc_driver_impl/Cargo.toml
+++ b/compiler/rustc_driver_impl/Cargo.toml
@@ -59,7 +59,7 @@ libc = "0.2"
 # tidy-alphabetical-end
 
 [target.'cfg(windows)'.dependencies.windows]
-version = "0.57.0"
+version = "0.59.0"
 features = [
     "Win32_System_Diagnostics_Debug",
 ]
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 0413e5e8634..20be2144609 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -28,8 +28,8 @@ use std::io::{self, IsTerminal, Read, Write};
 use std::panic::{self, PanicHookInfo, catch_unwind};
 use std::path::{Path, PathBuf};
 use std::process::{self, Command, Stdio};
+use std::sync::OnceLock;
 use std::sync::atomic::{AtomicBool, Ordering};
-use std::sync::{Arc, OnceLock};
 use std::time::{Instant, SystemTime};
 use std::{env, str};
 
@@ -53,14 +53,13 @@ use rustc_middle::ty::TyCtxt;
 use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
 use rustc_session::config::{
     CG_OPTIONS, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType, UnstableOptions,
-    Z_OPTIONS, nightly_options,
+    Z_OPTIONS, nightly_options, parse_target_triple,
 };
 use rustc_session::getopts::{self, Matches};
 use rustc_session::lint::{Lint, LintId};
 use rustc_session::output::collect_crate_types;
 use rustc_session::{EarlyDiagCtxt, Session, config, filesearch};
 use rustc_span::FileName;
-use rustc_span::source_map::FileLoader;
 use rustc_target::json::ToJson;
 use rustc_target::spec::{Target, TargetTuple};
 use time::OffsetDateTime;
@@ -208,84 +207,7 @@ pub fn diagnostics_registry() -> Registry {
 }
 
 /// This is the primary entry point for rustc.
-pub struct RunCompiler<'a> {
-    at_args: &'a [String],
-    callbacks: &'a mut (dyn Callbacks + Send),
-    file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
-    make_codegen_backend:
-        Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,
-    using_internal_features: Arc<std::sync::atomic::AtomicBool>,
-}
-
-impl<'a> RunCompiler<'a> {
-    pub fn new(at_args: &'a [String], callbacks: &'a mut (dyn Callbacks + Send)) -> Self {
-        Self {
-            at_args,
-            callbacks,
-            file_loader: None,
-            make_codegen_backend: None,
-            using_internal_features: Arc::default(),
-        }
-    }
-
-    /// Set a custom codegen backend.
-    ///
-    /// Has no uses within this repository, but is used by bjorn3 for "the
-    /// hotswapping branch of cg_clif" for "setting the codegen backend from a
-    /// custom driver where the custom codegen backend has arbitrary data."
-    /// (See #102759.)
-    pub fn set_make_codegen_backend(
-        &mut self,
-        make_codegen_backend: Option<
-            Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
-        >,
-    ) -> &mut Self {
-        self.make_codegen_backend = make_codegen_backend;
-        self
-    }
-
-    /// Load files from sources other than the file system.
-    ///
-    /// Has no uses within this repository, but may be used in the future by
-    /// bjorn3 for "hooking rust-analyzer's VFS into rustc at some point for
-    /// running rustc without having to save". (See #102759.)
-    pub fn set_file_loader(
-        &mut self,
-        file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
-    ) -> &mut Self {
-        self.file_loader = file_loader;
-        self
-    }
-
-    /// Set the session-global flag that checks whether internal features have been used,
-    /// suppressing the message about submitting an issue in ICEs when enabled.
-    #[must_use]
-    pub fn set_using_internal_features(mut self, using_internal_features: Arc<AtomicBool>) -> Self {
-        self.using_internal_features = using_internal_features;
-        self
-    }
-
-    /// Parse args and run the compiler.
-    pub fn run(self) {
-        run_compiler(
-            self.at_args,
-            self.callbacks,
-            self.file_loader,
-            self.make_codegen_backend,
-            self.using_internal_features,
-        );
-    }
-}
-
-fn run_compiler(
-    at_args: &[String],
-    callbacks: &mut (dyn Callbacks + Send),
-    file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
-    make_codegen_backend: Option<
-        Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
-    >,
-    using_internal_features: Arc<std::sync::atomic::AtomicBool>,
-) {
+pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) {
     let mut default_early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
 
     // Throw away the first argument, the name of the binary.
@@ -322,16 +244,16 @@ fn run_compiler(
         output_file: ofile,
         output_dir: odir,
         ice_file,
-        file_loader,
+        file_loader: None,
         locale_resources: DEFAULT_LOCALE_RESOURCES.to_vec(),
         lint_caps: Default::default(),
         psess_created: None,
         hash_untracked_state: None,
         register_lints: None,
         override_queries: None,
-        make_codegen_backend,
+        make_codegen_backend: None,
         registry: diagnostics_registry(),
-        using_internal_features,
+        using_internal_features: &USING_INTERNAL_FEATURES,
         expanded_args: args,
     };
 
@@ -916,13 +838,7 @@ pub fn version_at_macro_invocation(
         safe_println!("host: {}", config::host_tuple());
         safe_println!("release: {release}");
 
-        let debug_flags = matches.opt_strs("Z");
-        let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
-        let opts = config::Options::default();
-        let sysroot = filesearch::materialize_sysroot(opts.maybe_sysroot.clone());
-        let target = config::build_target_config(early_dcx, &opts, &sysroot);
-
-        get_codegen_backend(early_dcx, &sysroot, backend_name, &target).print_version();
+        get_backend_from_raw_matches(early_dcx, matches).print_version();
     }
 }
 
@@ -1125,19 +1041,32 @@ pub fn describe_flag_categories(early_dcx: &EarlyDiagCtxt, matches: &Matches) ->
     }
 
     if cg_flags.iter().any(|x| *x == "passes=list") {
-        let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
-
-        let opts = config::Options::default();
-        let sysroot = filesearch::materialize_sysroot(opts.maybe_sysroot.clone());
-        let target = config::build_target_config(early_dcx, &opts, &sysroot);
-
-        get_codegen_backend(early_dcx, &sysroot, backend_name, &target).print_passes();
+        get_backend_from_raw_matches(early_dcx, matches).print_passes();
         return true;
     }
 
     false
 }
 
+/// Get the codegen backend based on the raw [`Matches`].
+///
+/// `rustc -vV` and `rustc -Cpasses=list` need to get the codegen backend before we have parsed all
+/// arguments and created a [`Session`]. This function reads `-Zcodegen-backend`, `--target` and
+/// `--sysroot` without validating any other arguments and loads the codegen backend based on these
+/// arguments.
+fn get_backend_from_raw_matches(
+    early_dcx: &EarlyDiagCtxt,
+    matches: &Matches,
+) -> Box<dyn CodegenBackend> {
+    let debug_flags = matches.opt_strs("Z");
+    let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
+    let target = parse_target_triple(early_dcx, matches);
+    let sysroot = filesearch::materialize_sysroot(matches.opt_str("sysroot").map(PathBuf::from));
+    let target = config::build_target_config(early_dcx, &target, &sysroot);
+
+    get_codegen_backend(early_dcx, &sysroot, backend_name, &target)
+}
+
 fn describe_debug_flags() {
     safe_println!("\nAvailable options:\n");
     print_flag_list("-Z", config::Z_OPTIONS);
@@ -1191,15 +1120,6 @@ fn print_flag_list<T>(cmdline_opt: &str, flag_list: &[OptionDesc<T>]) {
 /// be public when using rustc as a library, see
 /// <https://github.com/rust-lang/rust/commit/2b4c33817a5aaecabf4c6598d41e190080ec119e>
 pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<getopts::Matches> {
-    if args.is_empty() {
-        // user did not write `-v` nor `-Z unstable-options`, so do not
-        // include that extra information.
-        let nightly_build =
-            rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build();
-        usage(false, false, nightly_build);
-        return None;
-    }
-
     // Parse with *all* options defined in the compiler, we don't worry about
     // option stability here we just want to parse as much as possible.
     let mut options = getopts::Options::new();
@@ -1245,7 +1165,7 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<geto
     //   (unstable option being used on stable)
     nightly_options::check_nightly_options(early_dcx, &matches, &config::rustc_optgroups());
 
-    if matches.opt_present("h") || matches.opt_present("help") {
+    if args.is_empty() || matches.opt_present("h") || matches.opt_present("help") {
         // Only show unstable options in --help if we accept unstable options.
         let unstable_enabled = nightly_options::is_unstable_enabled(&matches);
         let nightly_build = nightly_options::match_is_nightly_build(&matches);
@@ -1352,6 +1272,8 @@ fn ice_path_with_config(config: Option<&UnstableOptions>) -> &'static Option<Pat
     })
 }
 
+pub static USING_INTERNAL_FEATURES: AtomicBool = AtomicBool::new(false);
+
 /// Installs a panic hook that will print the ICE message on unexpected panics.
 ///
 /// The hook is intended to be useable even by external tools. You can pass a custom
@@ -1362,15 +1284,8 @@ fn ice_path_with_config(config: Option<&UnstableOptions>) -> &'static Option<Pat
 /// If you have no extra info to report, pass the empty closure `|_| ()` as the argument to
 /// extra_info.
 ///
-/// Returns a flag that can be set to disable the note for submitting a bug. This can be passed to
-/// [`RunCompiler::set_using_internal_features`] to let macro expansion set it when encountering
-/// internal features.
-///
 /// A custom rustc driver can skip calling this to set up a custom ICE hook.
-pub fn install_ice_hook(
-    bug_report_url: &'static str,
-    extra_info: fn(&DiagCtxt),
-) -> Arc<AtomicBool> {
+pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&DiagCtxt)) {
     // If the user has not explicitly overridden "RUST_BACKTRACE", then produce
     // full backtraces. When a compiler ICE happens, we want to gather
     // as much information as possible to present in the issue opened
@@ -1387,8 +1302,6 @@ pub fn install_ice_hook(
         }
     }
 
-    let using_internal_features = Arc::new(std::sync::atomic::AtomicBool::default());
-    let using_internal_features_hook = Arc::clone(&using_internal_features);
     panic::update_hook(Box::new(
         move |default_hook: &(dyn Fn(&PanicHookInfo<'_>) + Send + Sync + 'static),
               info: &PanicHookInfo<'_>| {
@@ -1440,11 +1353,9 @@ pub fn install_ice_hook(
             }
 
             // Print the ICE message
-            report_ice(info, bug_report_url, extra_info, &using_internal_features_hook);
+            report_ice(info, bug_report_url, extra_info, &USING_INTERNAL_FEATURES);
         },
     ));
-
-    using_internal_features
 }
 
 /// Prints the ICE message, including query stack, but without backtrace.
@@ -1530,9 +1441,9 @@ fn report_ice(
     // If backtraces are enabled, also print the query stack
     let backtrace = env::var_os("RUST_BACKTRACE").is_some_and(|x| &x != "0");
 
-    let num_frames = if backtrace { None } else { Some(2) };
+    let limit_frames = if backtrace { None } else { Some(2) };
 
-    interface::try_print_query_stack(dcx, num_frames, file);
+    interface::try_print_query_stack(dcx, limit_frames, file);
 
     // We don't trust this callback not to panic itself, so run it at the end after we're sure we've
     // printed all the relevant info.
@@ -1585,13 +1496,11 @@ pub fn main() -> ! {
     init_rustc_env_logger(&early_dcx);
     signal_handler::install();
     let mut callbacks = TimePassesCallbacks::default();
-    let using_internal_features = install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ());
+    install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ());
     install_ctrlc_handler();
 
     let exit_code = catch_with_exit_code(|| {
-        RunCompiler::new(&args::raw_args(&early_dcx)?, &mut callbacks)
-            .set_using_internal_features(using_internal_features)
-            .run();
+        run_compiler(&args::raw_args(&early_dcx)?, &mut callbacks);
         Ok(())
     });
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0038.md b/compiler/rustc_error_codes/src/error_codes/E0038.md
index 014d8c4f761..4b06395897a 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0038.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0038.md
@@ -264,15 +264,15 @@ trait Foo {
 ### Trait contains associated constants
 
 Just like static functions, associated constants aren't stored on the method
-table. If the trait or any subtrait contain an associated constant, they cannot
-be made into an object.
+table. If the trait or any subtrait contain an associated constant, they are not
+dyn compatible.
 
 ```compile_fail,E0038
 trait Foo {
     const X: i32;
 }
 
-impl Foo {}
+impl dyn Foo {}
 ```
 
 A simple workaround is to use a helper method instead:
diff --git a/compiler/rustc_error_codes/src/error_codes/E0132.md b/compiler/rustc_error_codes/src/error_codes/E0132.md
index 51258739b89..cbb14510ed7 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0132.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0132.md
@@ -1,32 +1,3 @@
-A function with the `start` attribute was declared with type parameters.
-
-Erroneous code example:
-
-```compile_fail,E0132
-#![feature(start)]
-
-#[start]
-fn f<T>() {}
-```
-
-It is not possible to declare type parameters on a function that has the `start`
-attribute. Such a function must have the following type signature (for more
-information, view [the unstable book][1]):
+#### Note: this error code is no longer emitted by the compiler.
 
-[1]: https://doc.rust-lang.org/unstable-book/language-features/start.html
-
-```
-# let _:
-fn(isize, *const *const u8) -> isize;
-```
-
-Example:
-
-```
-#![feature(start)]
-
-#[start]
-fn my_start(argc: isize, argv: *const *const u8) -> isize {
-    0
-}
-```
+A function with the `start` attribute was declared with type parameters.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0138.md b/compiler/rustc_error_codes/src/error_codes/E0138.md
index 3f5eaea9f98..2e6ba546a16 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0138.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0138.md
@@ -1,25 +1,3 @@
-More than one function was declared with the `#[start]` attribute.
-
-Erroneous code example:
-
-```compile_fail,E0138
-#![feature(start)]
-
-#[start]
-fn foo(argc: isize, argv: *const *const u8) -> isize {}
+#### Note: this error code is no longer emitted by the compiler.
 
-#[start]
-fn f(argc: isize, argv: *const *const u8) -> isize {}
-// error: multiple 'start' functions
-```
-
-This error indicates that the compiler found multiple functions with the
-`#[start]` attribute. This is an error because there must be a unique entry
-point into a Rust program. Example:
-
-```
-#![feature(start)]
-
-#[start]
-fn foo(argc: isize, argv: *const *const u8) -> isize { 0 } // ok!
-```
+More than one function was declared with the `#[start]` attribute.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0647.md b/compiler/rustc_error_codes/src/error_codes/E0647.md
index 59bb47ba62a..e2f14b81aa6 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0647.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0647.md
@@ -1,13 +1,3 @@
-The `start` function was defined with a where clause.
-
-Erroneous code example:
+#### Note: this error code is no longer emitted by the compiler.
 
-```compile_fail,E0647
-#![feature(start)]
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize where (): Copy {
-    //^ error: `#[start]` function is not allowed to have a where clause
-    0
-}
-```
+The `start` function was defined with a where clause.
diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs
index 29f3277d399..0a30bdb48a0 100644
--- a/compiler/rustc_error_codes/src/lib.rs
+++ b/compiler/rustc_error_codes/src/lib.rs
@@ -24,6 +24,10 @@
 //
 // Both columns are necessary because it's not possible in Rust to create a new identifier such as
 // `E0123` from an integer literal such as `0123`, unfortunately.
+//
+// Do *not* remove entries from this list. Instead, just add a note th the corresponding markdown
+// file saying that this error is not emitted by the compiler any more (see E0001.md for an
+// example), and remove all code examples that do not build any more.
 #[macro_export]
 macro_rules! error_codes {
     ($macro:path) => (
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index 66b9adbead0..fbb6a1cc475 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -31,7 +31,7 @@ tracing = "0.1"
 # tidy-alphabetical-end
 
 [target.'cfg(windows)'.dependencies.windows]
-version = "0.57.0"
+version = "0.59.0"
 features = [
     "Win32_Foundation",
     "Win32_Security",
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index f938352820d..991dfa1821a 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -3146,7 +3146,7 @@ impl FileWithAnnotatedLines {
                     add_annotation_to_file(&mut output, Lrc::clone(&file), line, ann.as_line());
                 }
                 let line_end = ann.line_end - 1;
-                let end_is_empty = file.get_line(line_end - 1).map_or(false, |s| !filter(&s));
+                let end_is_empty = file.get_line(line_end - 1).is_some_and(|s| !filter(&s));
                 if middle < line_end && !end_is_empty {
                     add_annotation_to_file(&mut output, Lrc::clone(&file), line_end, ann.as_line());
                 }
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index 97df7f9265a..c1188665a05 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -463,7 +463,8 @@ impl DiagnosticSpan {
         // is an empty string, increase the length to include the newline so we don't
         // leave an empty line
         if start.col.0 == 0
-            && suggestion.map_or(false, |(s, _)| s.is_empty())
+            && let Some((suggestion, _)) = suggestion
+            && suggestion.is_empty()
             && let Ok(after) = je.sm.span_to_next_source(span)
             && after.starts_with('\n')
         {
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index cc5eb9c335e..549729548f5 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -35,6 +35,7 @@ use std::backtrace::{Backtrace, BacktraceStatus};
 use std::borrow::Cow;
 use std::cell::Cell;
 use std::error::Report;
+use std::ffi::OsStr;
 use std::hash::Hash;
 use std::io::Write;
 use std::num::NonZero;
@@ -1717,7 +1718,7 @@ impl DiagCtxtInner {
         let bugs: Vec<_> =
             std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect();
 
-        let backtrace = std::env::var_os("RUST_BACKTRACE").map_or(true, |x| &x != "0");
+        let backtrace = std::env::var_os("RUST_BACKTRACE").as_deref() != Some(OsStr::new("0"));
         let decorate = backtrace || self.ice_file.is_none();
         let mut out = self
             .ice_file
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 3e3f35332e0..83255b82017 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -391,7 +391,7 @@ impl<'a> StripUnconfigured<'a> {
         validate_attr::deny_builtin_meta_unsafety(&self.sess.psess, &meta_item);
 
         (
-            parse_cfg(&meta_item, self.sess).map_or(true, |meta_item| {
+            parse_cfg(&meta_item, self.sess).is_none_or(|meta_item| {
                 attr::cfg_matches(meta_item, &self.sess, self.lint_node_id, self.features)
             }),
             Some(meta_item),
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index 9f48835e15d..e60a9e83184 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -159,7 +159,7 @@ impl<'dcx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'dcx, 'match
                 if self
                     .best_failure
                     .as_ref()
-                    .map_or(true, |failure| failure.is_better_position(*approx_position))
+                    .is_none_or(|failure| failure.is_better_position(*approx_position))
                 {
                     self.best_failure = Some(BestFailure {
                         token: token.clone(),
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index ef209c2bce1..21688521ade 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -282,11 +282,13 @@ pub(super) fn transcribe<'a>(
                         }
                         MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => {
                             marker.visit_span(&mut sp);
+                            with_metavar_spans(|mspans| mspans.insert(ident.span, sp));
                             let kind = token::NtIdent(*ident, *is_raw);
                             TokenTree::token_alone(kind, sp)
                         }
                         MatchedSingle(ParseNtResult::Lifetime(ident, is_raw)) => {
                             marker.visit_span(&mut sp);
+                            with_metavar_spans(|mspans| mspans.insert(ident.span, sp));
                             let kind = token::NtLifetime(*ident, *is_raw);
                             TokenTree::token_alone(kind, sp)
                         }
@@ -295,6 +297,8 @@ pub(super) fn transcribe<'a>(
                             // `Delimiter::Invisible` to maintain parsing priorities.
                             // `Interpolated` is currently used for such groups in rustc parser.
                             marker.visit_span(&mut sp);
+                            let use_span = nt.use_span();
+                            with_metavar_spans(|mspans| mspans.insert(use_span, sp));
                             TokenTree::token_alone(token::Interpolated(Lrc::clone(nt)), sp)
                         }
                         MatchedSeq(..) => {
@@ -410,19 +414,15 @@ fn maybe_use_metavar_location(
         return orig_tt.clone();
     }
 
-    let insert = |mspans: &mut FxHashMap<_, _>, s, ms| match mspans.try_insert(s, ms) {
-        Ok(_) => true,
-        Err(err) => *err.entry.get() == ms, // Tried to insert the same span, still success
-    };
     marker.visit_span(&mut metavar_span);
     let no_collision = match orig_tt {
         TokenTree::Token(token, ..) => {
-            with_metavar_spans(|mspans| insert(mspans, token.span, metavar_span))
+            with_metavar_spans(|mspans| mspans.insert(token.span, metavar_span))
         }
         TokenTree::Delimited(dspan, ..) => with_metavar_spans(|mspans| {
-            insert(mspans, dspan.open, metavar_span)
-                && insert(mspans, dspan.close, metavar_span)
-                && insert(mspans, dspan.entire(), metavar_span)
+            mspans.insert(dspan.open, metavar_span)
+                && mspans.insert(dspan.close, metavar_span)
+                && mspans.insert(dspan.entire(), metavar_span)
         }),
     };
     if no_collision || psess.source_map().is_imported(metavar_span) {
@@ -434,14 +434,14 @@ fn maybe_use_metavar_location(
     match orig_tt {
         TokenTree::Token(Token { kind, span }, spacing) => {
             let span = metavar_span.with_ctxt(span.ctxt());
-            with_metavar_spans(|mspans| insert(mspans, span, metavar_span));
+            with_metavar_spans(|mspans| mspans.insert(span, metavar_span));
             TokenTree::Token(Token { kind: kind.clone(), span }, *spacing)
         }
         TokenTree::Delimited(dspan, dspacing, delimiter, tts) => {
             let open = metavar_span.with_ctxt(dspan.open.ctxt());
             let close = metavar_span.with_ctxt(dspan.close.ctxt());
             with_metavar_spans(|mspans| {
-                insert(mspans, open, metavar_span) && insert(mspans, close, metavar_span)
+                mspans.insert(open, metavar_span) && mspans.insert(close, metavar_span)
             });
             let dspan = DelimSpan::from_pair(open, close);
             TokenTree::Delimited(dspan, *dspacing, *delimiter, tts.clone())
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 5510e7e09e5..68e0191f45e 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -448,7 +448,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
 
     // Entry point:
-    ungated!(start, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
     ungated!(no_start, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
     ungated!(no_main, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
 
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 9aa59375706..081638715df 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -163,7 +163,7 @@ declare_features! (
     /// then removed. But there was no utility storing it separately, so now
     /// it's in this list.
     (removed, no_stack_check, "1.0.0", None, None),
-    /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn-compatible (object safe).
+    /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn compatible (object safe).
     /// Renamed to `dyn_compatible_for_dispatch`.
     (removed, object_safe_for_dispatch, "1.83.0", Some(43561),
      Some("renamed to `dyn_compatible_for_dispatch`")),
@@ -220,8 +220,9 @@ declare_features! (
     (removed, rustc_diagnostic_macros, "1.38.0", None, None),
     /// Allows identifying crates that contain sanitizer runtimes.
     (removed, sanitizer_runtime, "1.17.0", None, None),
-    (removed, simd, "1.0.0", Some(27731),
-     Some("removed in favor of `#[repr(simd)]`")),
+    (removed, simd, "1.0.0", Some(27731), Some("removed in favor of `#[repr(simd)]`")),
+    /// Allows using `#[start]` on a function indicating that it is the program entrypoint.
+    (removed, start, "1.0.0", Some(29633), Some("not portable enough and never RFC'd")),
     /// Allows `#[link(kind = "static-nobundle", ...)]`.
     (removed, static_nobundle, "1.16.0", Some(37403),
      Some(r#"subsumed by `#[link(kind = "static", modifiers = "-bundle", ...)]`"#)),
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 1dcde453331..1a216ebf117 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -272,7 +272,7 @@ declare_features! (
     (unstable, doc_notable_trait, "1.52.0", Some(45040)),
     /// Allows using the `may_dangle` attribute (RFC 1327).
     (unstable, dropck_eyepatch, "1.10.0", Some(34761)),
-    /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn-compatible[^1].
+    /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn compatible[^1].
     /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and
     /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden.
     ///
@@ -300,8 +300,6 @@ declare_features! (
     (internal, rustdoc_internals, "1.58.0", Some(90418)),
     /// Allows using the `rustdoc::missing_doc_code_examples` lint
     (unstable, rustdoc_missing_doc_code_examples, "1.31.0", Some(101730)),
-    /// Allows using `#[start]` on a function indicating that it is the program entrypoint.
-    (unstable, start, "1.0.0", Some(29633)),
     /// Allows using `#[structural_match]` which indicates that a type is structurally matchable.
     /// FIXME: Subsumed by trait `StructuralPartialEq`, cannot move to removed until a library
     /// feature with the same name exists.
@@ -722,7 +720,8 @@ impl Features {
 
 /// Some features are not allowed to be used together at the same time, if
 /// the two are present, produce an error.
-///
-/// Currently empty, but we will probably need this again in the future,
-/// so let's keep it in for now.
-pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] = &[];
+pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] = &[
+    // Experimental match ergonomics rulesets are incompatible with each other, to simplify the
+    // boolean logic required to tell which typing rules to use.
+    (sym::ref_pat_eat_one_layer_2024, sym::ref_pat_eat_one_layer_2024_structural),
+];
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 705de389e07..7e3a8561da0 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -794,7 +794,7 @@ impl<Id> Res<Id> {
 
     /// Always returns `true` if `self` is `Res::Err`
     pub fn matches_ns(&self, ns: Namespace) -> bool {
-        self.ns().map_or(true, |actual_ns| actual_ns == ns)
+        self.ns().is_none_or(|actual_ns| actual_ns == ns)
     }
 
     /// Returns whether such a resolved path can occur in a tuple struct/variant pattern
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index fae3b778d7b..02bc069fc5f 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -332,6 +332,10 @@ language_item_table! {
     FallbackSurfaceDrop,     sym::fallback_surface_drop, fallback_surface_drop_fn, Target::Fn,             GenericRequirement::None;
     AllocLayout,             sym::alloc_layout,        alloc_layout,               Target::Struct,         GenericRequirement::None;
 
+    /// For all binary crates without `#![no_main]`, Rust will generate a "main" function.
+    /// The exact name and signature are target-dependent. The "main" function will invoke
+    /// this lang item, passing it the `argc` and `argv` (or null, if those don't exist
+    /// on the current target) as well as the user-defined `fn main` from the binary crate.
     Start,                   sym::start,               start_fn,                   Target::Fn,             GenericRequirement::Exact(1);
 
     EhPersonality,           sym::eh_personality,      eh_personality,             Target::Fn,             GenericRequirement::None;
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index d7ab6eca84b..512d379687b 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -489,21 +489,6 @@ hir_analysis_simd_ffi_highly_experimental = use of SIMD type{$snip} in FFI is hi
 hir_analysis_specialization_trait = implementing `rustc_specialization_trait` traits is unstable
     .help = add `#![feature(min_specialization)]` to the crate attributes to enable
 
-hir_analysis_start_function_parameters = `#[start]` function is not allowed to have type parameters
-    .label = `#[start]` function cannot have type parameters
-
-hir_analysis_start_function_where = `#[start]` function is not allowed to have a `where` clause
-    .label = `#[start]` function cannot have a `where` clause
-
-hir_analysis_start_not_async = `#[start]` function is not allowed to be `async`
-    .label = `#[start]` is not allowed to be `async`
-
-hir_analysis_start_not_target_feature = `#[start]` function is not allowed to have `#[target_feature]`
-    .label = `#[start]` function is not allowed to have `#[target_feature]`
-
-hir_analysis_start_not_track_caller = `#[start]` function is not allowed to be `#[track_caller]`
-    .label = `#[start]` function is not allowed to be `#[track_caller]`
-
 hir_analysis_static_specialize = cannot specialize on `'static` lifetime
 
 hir_analysis_tait_forward_compat = item constrains opaque type that is not in its signature
diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs
index d8e9227a87c..b3eade8c8ae 100644
--- a/compiler/rustc_hir_analysis/src/autoderef.rs
+++ b/compiler/rustc_hir_analysis/src/autoderef.rs
@@ -86,7 +86,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
                 if self.infcx.next_trait_solver()
                     && let ty::Alias(..) = ty.kind()
                 {
-                    let (normalized_ty, obligations) = self.structurally_normalize(ty)?;
+                    let (normalized_ty, obligations) = self.structurally_normalize_ty(ty)?;
                     self.state.obligations.extend(obligations);
                     (AutoderefKind::Builtin, normalized_ty)
                 } else {
@@ -166,7 +166,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
         }
 
         let (normalized_ty, obligations) =
-            self.structurally_normalize(Ty::new_projection(tcx, trait_target_def_id, [ty]))?;
+            self.structurally_normalize_ty(Ty::new_projection(tcx, trait_target_def_id, [ty]))?;
         debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
         self.state.obligations.extend(obligations);
 
@@ -174,12 +174,12 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self), ret)]
-    pub fn structurally_normalize(
+    pub fn structurally_normalize_ty(
         &self,
         ty: Ty<'tcx>,
     ) -> Option<(Ty<'tcx>, PredicateObligations<'tcx>)> {
         let ocx = ObligationCtxt::new(self.infcx);
-        let Ok(normalized_ty) = ocx.structurally_normalize(
+        let Ok(normalized_ty) = ocx.structurally_normalize_ty(
             &traits::ObligationCause::misc(self.span, self.body_id),
             self.param_env,
             ty,
diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs
index 332ac2fa0c0..25c2f8554b7 100644
--- a/compiler/rustc_hir_analysis/src/check/entry.rs
+++ b/compiler/rustc_hir_analysis/src/check/entry.rs
@@ -5,7 +5,7 @@ use rustc_hir as hir;
 use rustc_hir::Node;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::span_bug;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode};
+use rustc_middle::ty::{self, TyCtxt, TypingMode};
 use rustc_session::config::EntryFnType;
 use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
 use rustc_span::{Span, sym};
@@ -18,7 +18,6 @@ use crate::errors;
 pub(crate) fn check_for_entry_fn(tcx: TyCtxt<'_>) {
     match tcx.entry_fn(()) {
         Some((def_id, EntryFnType::Main { .. })) => check_main_fn_ty(tcx, def_id),
-        Some((def_id, EntryFnType::Start)) => check_start_fn_ty(tcx, def_id),
         _ => {}
     }
 }
@@ -192,83 +191,3 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
         });
     }
 }
-
-fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
-    let start_def_id = start_def_id.expect_local();
-    let start_id = tcx.local_def_id_to_hir_id(start_def_id);
-    let start_span = tcx.def_span(start_def_id);
-    let start_t = tcx.type_of(start_def_id).instantiate_identity();
-    match start_t.kind() {
-        ty::FnDef(..) => {
-            if let Node::Item(it) = tcx.hir_node(start_id) {
-                if let hir::ItemKind::Fn { sig, generics, .. } = &it.kind {
-                    let mut error = false;
-                    if !generics.params.is_empty() {
-                        tcx.dcx().emit_err(errors::StartFunctionParameters { span: generics.span });
-                        error = true;
-                    }
-                    if generics.has_where_clause_predicates {
-                        tcx.dcx().emit_err(errors::StartFunctionWhere {
-                            span: generics.where_clause_span,
-                        });
-                        error = true;
-                    }
-                    if sig.header.asyncness.is_async() {
-                        let span = tcx.def_span(it.owner_id);
-                        tcx.dcx().emit_err(errors::StartAsync { span });
-                        error = true;
-                    }
-
-                    let attrs = tcx.hir().attrs(start_id);
-                    for attr in attrs {
-                        if attr.has_name(sym::track_caller) {
-                            tcx.dcx().emit_err(errors::StartTrackCaller {
-                                span: attr.span,
-                                start: start_span,
-                            });
-                            error = true;
-                        }
-                        if attr.has_name(sym::target_feature)
-                            // Calling functions with `#[target_feature]` is
-                            // not unsafe on WASM, see #84988
-                            && !tcx.sess.target.is_like_wasm
-                            && !tcx.sess.opts.actually_rustdoc
-                        {
-                            tcx.dcx().emit_err(errors::StartTargetFeature {
-                                span: attr.span,
-                                start: start_span,
-                            });
-                            error = true;
-                        }
-                    }
-
-                    if error {
-                        return;
-                    }
-                }
-            }
-
-            let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig(
-                [tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))],
-                tcx.types.isize,
-                false,
-                hir::Safety::Safe,
-                ExternAbi::Rust,
-            ));
-
-            let _ = check_function_signature(
-                tcx,
-                ObligationCause::new(
-                    start_span,
-                    start_def_id,
-                    ObligationCauseCode::StartFunctionType,
-                ),
-                start_def_id.into(),
-                expected_sig,
-            );
-        }
-        _ => {
-            span_bug!(start_span, "start has a non-function type: found `{}`", start_t);
-        }
-    }
-}
diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs
index 1be4aa2f63a..4e5f0a3186a 100644
--- a/compiler/rustc_hir_analysis/src/coherence/mod.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs
@@ -13,6 +13,7 @@ use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
 use rustc_session::parse::feature_err;
 use rustc_span::{ErrorGuaranteed, sym};
+use rustc_type_ir::elaborate;
 use tracing::debug;
 
 use crate::errors;
@@ -184,7 +185,7 @@ fn check_object_overlap<'tcx>(
     // check for overlap with the automatic `impl Trait for dyn Trait`
     if let ty::Dynamic(data, ..) = trait_ref.self_ty().kind() {
         // This is something like `impl Trait1 for Trait2`. Illegal if
-        // Trait1 is a supertrait of Trait2 or Trait2 is not dyn-compatible.
+        // Trait1 is a supertrait of Trait2 or Trait2 is not dyn compatible.
 
         let component_def_ids = data.iter().flat_map(|predicate| {
             match predicate.skip_binder() {
@@ -205,7 +206,7 @@ fn check_object_overlap<'tcx>(
                 // With the feature enabled, the trait is not implemented automatically,
                 // so this is valid.
             } else {
-                let mut supertrait_def_ids = tcx.supertrait_def_ids(component_def_id);
+                let mut supertrait_def_ids = elaborate::supertrait_def_ids(tcx, component_def_id);
                 if supertrait_def_ids
                     .any(|d| d == trait_def_id && tcx.trait_def(d).implement_via_object)
                 {
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 7d651155781..d17ee86ba66 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -320,7 +320,7 @@ fn orphan_check<'tcx>(
         }
 
         let ty = if infcx.next_trait_solver() {
-            ocx.structurally_normalize(
+            ocx.structurally_normalize_ty(
                 &cause,
                 ty::ParamEnv::empty(),
                 infcx.resolve_vars_if_possible(ty),
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 00ba1741ed7..a0f365142ba 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -620,48 +620,6 @@ pub(crate) struct TargetFeatureOnMain {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis_start_not_track_caller)]
-pub(crate) struct StartTrackCaller {
-    #[primary_span]
-    pub span: Span,
-    #[label]
-    pub start: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis_start_not_target_feature)]
-pub(crate) struct StartTargetFeature {
-    #[primary_span]
-    pub span: Span,
-    #[label]
-    pub start: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis_start_not_async, code = E0752)]
-pub(crate) struct StartAsync {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis_start_function_where, code = E0647)]
-pub(crate) struct StartFunctionWhere {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis_start_function_parameters, code = E0132)]
-pub(crate) struct StartFunctionParameters {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(hir_analysis_main_function_return_type_generic, code = E0131)]
 pub(crate) struct MainFunctionReturnTypeGeneric {
     #[primary_span]
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index 71a5727ed6c..72ad190df7e 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -4,13 +4,12 @@ use rustc_errors::struct_span_code_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
-use rustc_middle::span_bug;
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::{
     self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable,
     TypeVisitableExt, Upcast,
 };
-use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
+use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
 use rustc_trait_selection::traits::{self, hir_ty_lowering_dyn_compatibility_violations};
 use rustc_type_ir::elaborate::ClauseWithSupertraitSpan;
@@ -30,16 +29,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         &self,
         span: Span,
         hir_id: hir::HirId,
-        hir_trait_bounds: &[hir::PolyTraitRef<'tcx>],
+        hir_bounds: &[hir::PolyTraitRef<'tcx>],
         lifetime: &hir::Lifetime,
         representation: DynKind,
     ) -> Ty<'tcx> {
         let tcx = self.tcx();
+        let dummy_self = tcx.types.trait_object_dummy_self;
 
-        let mut bounds = Bounds::default();
+        let mut user_written_bounds = Bounds::default();
         let mut potential_assoc_types = Vec::new();
-        let dummy_self = self.tcx().types.trait_object_dummy_self;
-        for trait_bound in hir_trait_bounds.iter().rev() {
+        for trait_bound in hir_bounds.iter() {
             if let hir::BoundPolarity::Maybe(_) = trait_bound.modifiers.polarity {
                 continue;
             }
@@ -53,92 +52,67 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 hir::BoundConstness::Never,
                 hir::BoundPolarity::Positive,
                 dummy_self,
-                &mut bounds,
+                &mut user_written_bounds,
                 PredicateFilter::SelfOnly,
             ) {
                 potential_assoc_types.extend(cur_potential_assoc_types);
             }
         }
 
-        let mut trait_bounds = vec![];
-        let mut projection_bounds = vec![];
-        for (pred, span) in bounds.clauses() {
-            let bound_pred = pred.kind();
-            match bound_pred.skip_binder() {
-                ty::ClauseKind::Trait(trait_pred) => {
-                    assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
-                    trait_bounds.push((bound_pred.rebind(trait_pred.trait_ref), span));
-                }
-                ty::ClauseKind::Projection(proj) => {
-                    projection_bounds.push((bound_pred.rebind(proj), span));
-                }
-                ty::ClauseKind::TypeOutlives(_) => {
-                    // Do nothing, we deal with regions separately
-                }
-                ty::ClauseKind::RegionOutlives(_)
-                | ty::ClauseKind::ConstArgHasType(..)
-                | ty::ClauseKind::WellFormed(_)
-                | ty::ClauseKind::ConstEvaluatable(_)
-                | ty::ClauseKind::HostEffect(..) => {
-                    span_bug!(span, "did not expect {pred} clause in object bounds");
-                }
-            }
-        }
-
-        // Expand trait aliases recursively and check that only one regular (non-auto) trait
-        // is used and no 'maybe' bounds are used.
-        let expanded_traits =
-            traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b)| (a, b)));
-
-        let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
-            expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
+        let (trait_bounds, mut projection_bounds) =
+            traits::expand_trait_aliases(tcx, user_written_bounds.clauses());
+        let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = trait_bounds
+            .into_iter()
+            .partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
 
+        // We  don't support empty trait objects.
+        if regular_traits.is_empty() && auto_traits.is_empty() {
+            let guar =
+                self.report_trait_object_with_no_traits_error(span, user_written_bounds.clauses());
+            return Ty::new_error(tcx, guar);
+        }
         // We don't support >1 principal
         if regular_traits.len() > 1 {
             let guar = self.report_trait_object_addition_traits_error(&regular_traits);
             return Ty::new_error(tcx, guar);
         }
-        // We  don't support empty trait objects.
-        if regular_traits.is_empty() && auto_traits.is_empty() {
-            let guar = self.report_trait_object_with_no_traits_error(span, &trait_bounds);
-            return Ty::new_error(tcx, guar);
-        }
         // Don't create a dyn trait if we have errors in the principal.
-        if let Err(guar) = trait_bounds.error_reported() {
+        if let Err(guar) = regular_traits.error_reported() {
             return Ty::new_error(tcx, guar);
         }
 
         // Check that there are no gross dyn-compatibility violations;
         // most importantly, that the supertraits don't contain `Self`,
         // to avoid ICEs.
-        for item in &regular_traits {
-            let violations =
-                hir_ty_lowering_dyn_compatibility_violations(tcx, item.trait_ref().def_id());
-            if !violations.is_empty() {
-                let reported = report_dyn_incompatibility(
-                    tcx,
-                    span,
-                    Some(hir_id),
-                    item.trait_ref().def_id(),
-                    &violations,
-                )
-                .emit();
-                return Ty::new_error(tcx, reported);
+        for (clause, span) in user_written_bounds.clauses() {
+            if let Some(trait_pred) = clause.as_trait_clause() {
+                let violations =
+                    hir_ty_lowering_dyn_compatibility_violations(tcx, trait_pred.def_id());
+                if !violations.is_empty() {
+                    let reported = report_dyn_incompatibility(
+                        tcx,
+                        span,
+                        Some(hir_id),
+                        trait_pred.def_id(),
+                        &violations,
+                    )
+                    .emit();
+                    return Ty::new_error(tcx, reported);
+                }
             }
         }
 
-        let mut needed_associated_types = FxIndexSet::default();
-
-        let principal_span = regular_traits.first().map_or(DUMMY_SP, |info| info.bottom().1);
-        let regular_traits_refs_spans = trait_bounds
-            .into_iter()
-            .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
+        let principal_trait = regular_traits.into_iter().next();
 
-        for (base_trait_ref, original_span) in regular_traits_refs_spans {
-            let base_pred: ty::Predicate<'tcx> = base_trait_ref.upcast(tcx);
+        let mut needed_associated_types = FxIndexSet::default();
+        if let Some((principal_trait, spans)) = &principal_trait {
+            let pred: ty::Predicate<'tcx> = (*principal_trait).upcast(tcx);
             for ClauseWithSupertraitSpan { pred, supertrait_span } in
-                traits::elaborate(tcx, [ClauseWithSupertraitSpan::new(base_pred, original_span)])
-                    .filter_only_self()
+                traits::elaborate(tcx, [ClauseWithSupertraitSpan::new(
+                    pred,
+                    *spans.last().unwrap(),
+                )])
+                .filter_only_self()
             {
                 debug!("observing object predicate `{pred:?}`");
 
@@ -179,7 +153,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         //     }
                         // ```
                         //
-                        // Here, the user could theoretically write `dyn MyTrait<Output = X>`,
+                        // Here, the user could theoretically write `dyn MyTrait<MyOutput = X>`,
                         // but actually supporting that would "expand" to an infinitely-long type
                         // `fix $ τ → dyn MyTrait<MyOutput = X, Output = <τ as MyTrait>::MyOutput`.
                         //
@@ -188,12 +162,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         // the discussion in #56288 for alternatives.
                         if !references_self {
                             // Include projections defined on supertraits.
-                            projection_bounds.push((pred, original_span));
+                            projection_bounds.push((pred, supertrait_span));
                         }
 
                         self.check_elaborated_projection_mentions_input_lifetimes(
                             pred,
-                            original_span,
+                            *spans.first().unwrap(),
                             supertrait_span,
                         );
                     }
@@ -202,11 +176,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
         }
 
-        // `dyn Trait<Assoc = Foo>` desugars to (not Rust syntax) `dyn Trait where <Self as Trait>::Assoc = Foo`.
-        // So every `Projection` clause is an `Assoc = Foo` bound. `associated_types` contains all associated
-        // types's `DefId`, so the following loop removes all the `DefIds` of the associated types that have a
-        // corresponding `Projection` clause
-        for (projection_bound, span) in &projection_bounds {
+        // `dyn Trait<Assoc = Foo>` desugars to (not Rust syntax) `dyn Trait where
+        // <Self as Trait>::Assoc = Foo`. So every `Projection` clause is an
+        // `Assoc = Foo` bound. `needed_associated_types` contains all associated
+        // types that we expect to be provided by the user, so the following loop
+        // removes all the associated types that have a corresponding `Projection`
+        // clause, either from expanding trait aliases or written by the user.
+        for &(projection_bound, span) in &projection_bounds {
             let def_id = projection_bound.item_def_id();
             let trait_ref = tcx.anonymize_bound_vars(
                 projection_bound.map_bound(|p| p.projection_term.trait_ref(tcx)),
@@ -216,17 +192,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 tcx.emit_node_span_lint(
                     UNUSED_ASSOCIATED_TYPE_BOUNDS,
                     hir_id,
-                    *span,
-                    crate::errors::UnusedAssociatedTypeBounds { span: *span },
+                    span,
+                    crate::errors::UnusedAssociatedTypeBounds { span },
                 );
             }
         }
 
         if let Err(guar) = self.check_for_required_assoc_tys(
-            principal_span,
+            principal_trait.as_ref().map_or(smallvec![], |(_, spans)| spans.clone()),
             needed_associated_types,
             potential_assoc_types,
-            hir_trait_bounds,
+            hir_bounds,
         ) {
             return Ty::new_error(tcx, guar);
         }
@@ -236,32 +212,36 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         // We remove duplicates by inserting into a `FxHashSet` to avoid re-ordering
         // the bounds
         let mut duplicates = FxHashSet::default();
-        auto_traits.retain(|i| duplicates.insert(i.trait_ref().def_id()));
-        debug!(?regular_traits);
+        auto_traits.retain(|(trait_pred, _)| duplicates.insert(trait_pred.def_id()));
+
+        debug!(?principal_trait);
         debug!(?auto_traits);
 
         // Erase the `dummy_self` (`trait_object_dummy_self`) used above.
-        let existential_trait_refs = regular_traits.iter().map(|i| {
-            i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| {
+        let principal_trait_ref = principal_trait.map(|(trait_pred, spans)| {
+            trait_pred.map_bound(|trait_pred| {
+                let trait_ref = trait_pred.trait_ref;
+                assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
                 assert_eq!(trait_ref.self_ty(), dummy_self);
 
+                let span = *spans.first().unwrap();
+
                 // Verify that `dummy_self` did not leak inside default type parameters. This
                 // could not be done at path creation, since we need to see through trait aliases.
                 let mut missing_type_params = vec![];
-                let mut references_self = false;
                 let generics = tcx.generics_of(trait_ref.def_id);
                 let args: Vec<_> = trait_ref
                     .args
                     .iter()
                     .enumerate()
-                    .skip(1) // Remove `Self` for `ExistentialPredicate`.
+                    // Skip `Self`
+                    .skip(1)
                     .map(|(index, arg)| {
                         if arg == dummy_self.into() {
                             let param = &generics.own_params[index];
                             missing_type_params.push(param.name);
                             Ty::new_misc_error(tcx).into()
                         } else if arg.walk().any(|arg| arg == dummy_self.into()) {
-                            references_self = true;
                             let guar = self.dcx().span_delayed_bug(
                                 span,
                                 "trait object trait bounds reference `Self`",
@@ -273,8 +253,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     })
                     .collect();
 
-                let span = i.bottom().1;
-                let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| {
+                let empty_generic_args = hir_bounds.iter().any(|hir_bound| {
                     hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
                         && hir_bound.span.contains(span)
                 });
@@ -285,26 +264,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     empty_generic_args,
                 );
 
-                if references_self {
-                    let def_id = i.bottom().0.def_id();
-                    struct_span_code_err!(
-                        self.dcx(),
-                        i.bottom().1,
-                        E0038,
-                        "the {} `{}` cannot be made into an object",
-                        tcx.def_descr(def_id),
-                        tcx.item_name(def_id),
-                    )
-                    .with_note(
-                        rustc_middle::traits::DynCompatibilityViolation::SupertraitSelf(
-                            smallvec![],
-                        )
-                        .error_msg(),
-                    )
-                    .emit();
-                }
-
-                ty::ExistentialTraitRef::new(tcx, trait_ref.def_id, args)
+                ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::new(
+                    tcx,
+                    trait_ref.def_id,
+                    args,
+                ))
             })
         });
 
@@ -327,21 +291,24 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     b.projection_term = replace_dummy_self_with_error(tcx, b.projection_term, guar);
                 }
 
-                ty::ExistentialProjection::erase_self_ty(tcx, b)
+                ty::ExistentialPredicate::Projection(ty::ExistentialProjection::erase_self_ty(
+                    tcx, b,
+                ))
             })
         });
 
-        let regular_trait_predicates = existential_trait_refs
-            .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait));
-        let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| {
-            ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id()))
+        let auto_trait_predicates = auto_traits.into_iter().map(|(trait_pred, _)| {
+            assert_eq!(trait_pred.polarity(), ty::PredicatePolarity::Positive);
+            assert_eq!(trait_pred.self_ty().skip_binder(), dummy_self);
+
+            ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_pred.def_id()))
         });
+
         // N.b. principal, projections, auto traits
         // FIXME: This is actually wrong with multiple principals in regards to symbol mangling
-        let mut v = regular_trait_predicates
-            .chain(
-                existential_projections.map(|x| x.map_bound(ty::ExistentialPredicate::Projection)),
-            )
+        let mut v = principal_trait_ref
+            .into_iter()
+            .chain(existential_projections)
             .chain(auto_trait_predicates)
             .collect::<SmallVec<[_; 8]>>();
         v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index 7a3d921f00e..5d751a25080 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -11,7 +11,7 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::bug;
 use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
 use rustc_middle::ty::{
-    self, AdtDef, Binder, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeVisitableExt,
+    self, AdtDef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt,
     suggest_constraining_type_param,
 };
 use rustc_session::parse::feature_err;
@@ -19,8 +19,9 @@ use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym};
 use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
 use rustc_trait_selection::traits::{
-    FulfillmentError, TraitAliasExpansionInfo, dyn_compatibility_violations_for_assoc_item,
+    FulfillmentError, dyn_compatibility_violations_for_assoc_item,
 };
+use smallvec::SmallVec;
 
 use crate::errors::{
     self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams,
@@ -720,7 +721,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// emit a generic note suggesting using a `where` clause to constraint instead.
     pub(crate) fn check_for_required_assoc_tys(
         &self,
-        principal_span: Span,
+        spans: SmallVec<[Span; 1]>,
         missing_assoc_types: FxIndexSet<(DefId, ty::PolyTraitRef<'tcx>)>,
         potential_assoc_types: Vec<usize>,
         trait_bounds: &[hir::PolyTraitRef<'_>],
@@ -729,6 +730,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             return Ok(());
         }
 
+        let principal_span = *spans.first().unwrap();
+
         let tcx = self.tcx();
         // FIXME: This logic needs some more care w.r.t handling of conflicts
         let missing_assoc_types: Vec<_> = missing_assoc_types
@@ -1124,29 +1127,36 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
     pub fn report_trait_object_addition_traits_error(
         &self,
-        regular_traits: &Vec<TraitAliasExpansionInfo<'_>>,
+        regular_traits: &Vec<(ty::PolyTraitPredicate<'tcx>, SmallVec<[Span; 1]>)>,
     ) -> ErrorGuaranteed {
-        let first_trait = &regular_traits[0];
-        let additional_trait = &regular_traits[1];
+        // we use the last span to point at the traits themselves,
+        // and all other preceding spans are trait alias expansions.
+        let (&first_span, first_alias_spans) = regular_traits[0].1.split_last().unwrap();
+        let (&second_span, second_alias_spans) = regular_traits[1].1.split_last().unwrap();
         let mut err = struct_span_code_err!(
             self.dcx(),
-            additional_trait.bottom().1,
+            *regular_traits[1].1.first().unwrap(),
             E0225,
             "only auto traits can be used as additional traits in a trait object"
         );
-        additional_trait.label_with_exp_info(
-            &mut err,
-            "additional non-auto trait",
-            "additional use",
-        );
-        first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use");
+        err.span_label(first_span, "first non-auto trait");
+        for &alias_span in first_alias_spans {
+            err.span_label(alias_span, "first non-auto trait comes from this alias");
+        }
+        err.span_label(second_span, "additional non-auto trait");
+        for &alias_span in second_alias_spans {
+            err.span_label(alias_span, "second non-auto trait comes from this alias");
+        }
         err.help(format!(
             "consider creating a new trait with all of these as supertraits and using that \
              trait here instead: `trait NewTrait: {} {{}}`",
             regular_traits
                 .iter()
                 // FIXME: This should `print_sugared`, but also needs to integrate projection bounds...
-                .map(|t| t.trait_ref().print_only_trait_path().to_string())
+                .map(|(pred, _)| pred
+                    .map_bound(|pred| pred.trait_ref)
+                    .print_only_trait_path()
+                    .to_string())
                 .collect::<Vec<_>>()
                 .join(" + "),
         ));
@@ -1161,14 +1171,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     pub fn report_trait_object_with_no_traits_error(
         &self,
         span: Span,
-        trait_bounds: &Vec<(Binder<'tcx, TraitRef<'tcx>>, Span)>,
+        user_written_clauses: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
     ) -> ErrorGuaranteed {
         let tcx = self.tcx();
-        let trait_alias_span = trait_bounds
-            .iter()
-            .map(|&(trait_ref, _)| trait_ref.def_id())
-            .find(|&trait_ref| tcx.is_trait_alias(trait_ref))
-            .map(|trait_ref| tcx.def_span(trait_ref));
+        let trait_alias_span = user_written_clauses
+            .into_iter()
+            .filter_map(|(clause, _)| clause.as_trait_clause())
+            .find(|trait_ref| tcx.is_trait_alias(trait_ref.def_id()))
+            .map(|trait_ref| tcx.def_span(trait_ref.def_id()));
 
         self.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span })
     }
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 7b07e0ee939..5d00ecbe918 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -45,6 +45,7 @@ use rustc_session::lint;
 use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::{DUMMY_SP, Span, sym};
 use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_type_ir::elaborate;
 use tracing::{debug, instrument};
 
 use super::FnCtxt;
@@ -923,7 +924,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                         let src_auto: FxHashSet<_> = src_tty
                             .auto_traits()
                             .chain(
-                                tcx.supertrait_def_ids(src_principal.def_id())
+                                elaborate::supertrait_def_ids(tcx, src_principal.def_id())
                                     .filter(|def_id| tcx.trait_is_auto(*def_id)),
                             )
                             .collect();
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 6945dbc3216..47abba1cc29 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -461,9 +461,17 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         // to the target type), since that should be the least
         // confusing.
         let Some(InferOk { value: ty, mut obligations }) = found else {
-            let err = first_error.expect("coerce_borrowed_pointer had no error");
-            debug!("coerce_borrowed_pointer: failed with err = {:?}", err);
-            return Err(err);
+            if let Some(first_error) = first_error {
+                debug!("coerce_borrowed_pointer: failed with err = {:?}", first_error);
+                return Err(first_error);
+            } else {
+                // This may happen in the new trait solver since autoderef requires
+                // the pointee to be structurally normalizable, or else it'll just bail.
+                // So when we have a type like `&<not well formed>`, then we get no
+                // autoderef steps (even though there should be at least one). That means
+                // we get no type mismatches, since the loop above just exits early.
+                return Err(TypeError::Mismatch);
+            }
         };
 
         if ty == a && mt_a.mutbl.is_not() && autoderef.step_count() == 1 {
@@ -1124,7 +1132,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 if self.next_trait_solver()
                     && let ty::Alias(..) = ty.kind()
                 {
-                    ocx.structurally_normalize(&cause, self.param_env, ty)
+                    ocx.structurally_normalize_ty(&cause, self.param_env, ty)
                 } else {
                     Ok(ty)
                 }
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 4eed2bc1238..052adaa69b2 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -19,8 +19,15 @@ use crate::fluent_generated as fluent;
 pub(crate) struct BaseExpressionDoubleDot {
     #[primary_span]
     pub span: Span,
+    #[suggestion(
+        hir_typeck_base_expression_double_dot_enable_default_field_values,
+        code = "#![feature(default_field_values)]\n",
+        applicability = "machine-applicable",
+        style = "verbose"
+    )]
+    pub default_field_values_suggestion: Option<Span>,
     #[subdiagnostic]
-    pub default_field_values: Option<BaseExpressionDoubleDotEnableDefaultFieldValues>,
+    pub default_field_values_help: Option<BaseExpressionDoubleDotEnableDefaultFieldValues>,
     #[subdiagnostic]
     pub add_expr: Option<BaseExpressionDoubleDotAddExpr>,
     #[subdiagnostic]
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 3bb518e7f97..bdd436302f4 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -1991,18 +1991,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         adt_ty: Ty<'tcx>,
         expected: Expectation<'tcx>,
         expr: &hir::Expr<'_>,
-        span: Span,
+        path_span: Span,
         variant: &'tcx ty::VariantDef,
         hir_fields: &'tcx [hir::ExprField<'tcx>],
         base_expr: &'tcx hir::StructTailExpr<'tcx>,
     ) {
         let tcx = self.tcx;
 
-        let adt_ty = self.try_structurally_resolve_type(span, adt_ty);
+        let adt_ty = self.try_structurally_resolve_type(path_span, adt_ty);
         let adt_ty_hint = expected.only_has_type(self).and_then(|expected| {
             self.fudge_inference_if_ok(|| {
                 let ocx = ObligationCtxt::new(self);
-                ocx.sup(&self.misc(span), self.param_env, expected, adt_ty)?;
+                ocx.sup(&self.misc(path_span), self.param_env, expected, adt_ty)?;
                 if !ocx.select_where_possible().is_empty() {
                     return Err(TypeError::Mismatch);
                 }
@@ -2012,11 +2012,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         });
         if let Some(adt_ty_hint) = adt_ty_hint {
             // re-link the variables that the fudging above can create.
-            self.demand_eqtype(span, adt_ty_hint, adt_ty);
+            self.demand_eqtype(path_span, adt_ty_hint, adt_ty);
         }
 
         let ty::Adt(adt, args) = adt_ty.kind() else {
-            span_bug!(span, "non-ADT passed to check_expr_struct_fields");
+            span_bug!(path_span, "non-ADT passed to check_expr_struct_fields");
         };
         let adt_kind = adt.adt_kind();
 
@@ -2107,7 +2107,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         if adt_kind == AdtKind::Union && hir_fields.len() != 1 {
             struct_span_code_err!(
                 self.dcx(),
-                span,
+                path_span,
                 E0784,
                 "union expressions should have exactly one field",
             )
@@ -2138,13 +2138,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
             if !self.tcx.features().default_field_values() {
+                let sugg = self.tcx.crate_level_attribute_injection_span(expr.hir_id);
                 self.dcx().emit_err(BaseExpressionDoubleDot {
                     span: span.shrink_to_hi(),
                     // We only mention enabling the feature if this is a nightly rustc *and* the
                     // expression would make sense with the feature enabled.
-                    default_field_values: if self.tcx.sess.is_nightly_build()
+                    default_field_values_suggestion: if self.tcx.sess.is_nightly_build()
+                        && missing_mandatory_fields.is_empty()
+                        && !missing_optional_fields.is_empty()
+                        && sugg.is_some()
+                    {
+                        sugg
+                    } else {
+                        None
+                    },
+                    default_field_values_help: if self.tcx.sess.is_nightly_build()
                         && missing_mandatory_fields.is_empty()
                         && !missing_optional_fields.is_empty()
+                        && sugg.is_none()
                     {
                         Some(BaseExpressionDoubleDotEnableDefaultFieldValues)
                     } else {
@@ -2167,6 +2178,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 });
                 return;
             }
+            if variant.fields.is_empty() {
+                let mut err = self.dcx().struct_span_err(
+                    span,
+                    format!(
+                        "`{adt_ty}` has no fields, `..` needs at least one default field in the \
+                         struct definition",
+                    ),
+                );
+                err.span_label(path_span, "this type has no fields");
+                err.emit();
+            }
             if !missing_mandatory_fields.is_empty() {
                 let s = pluralize!(missing_mandatory_fields.len());
                 let fields: Vec<_> =
@@ -2316,11 +2338,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .collect();
 
             if !private_fields.is_empty() {
-                self.report_private_fields(adt_ty, span, expr.span, private_fields, hir_fields);
+                self.report_private_fields(
+                    adt_ty,
+                    path_span,
+                    expr.span,
+                    private_fields,
+                    hir_fields,
+                );
             } else {
                 self.report_missing_fields(
                     adt_ty,
-                    span,
+                    path_span,
+                    expr.span,
                     remaining_fields,
                     variant,
                     hir_fields,
@@ -2358,6 +2387,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         adt_ty: Ty<'tcx>,
         span: Span,
+        full_span: Span,
         remaining_fields: UnordMap<Ident, (FieldIdx, &ty::FieldDef)>,
         variant: &'tcx ty::VariantDef,
         hir_fields: &'tcx [hir::ExprField<'tcx>],
@@ -2397,6 +2427,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         );
         err.span_label(span, format!("missing {remaining_fields_names}{truncated_fields_error}"));
 
+        if remaining_fields.items().all(|(_, (_, field))| field.value.is_some())
+            && self.tcx.sess.is_nightly_build()
+        {
+            let msg = format!(
+                "all remaining fields have default values, {you_can} use those values with `..`",
+                you_can = if self.tcx.features().default_field_values() {
+                    "you can"
+                } else {
+                    "if you added `#![feature(default_field_values)]` to your crate you could"
+                },
+            );
+            if let Some(hir_field) = hir_fields.last() {
+                err.span_suggestion_verbose(
+                    hir_field.span.shrink_to_hi(),
+                    msg,
+                    ", ..".to_string(),
+                    Applicability::MachineApplicable,
+                );
+            } else if hir_fields.is_empty() {
+                err.span_suggestion_verbose(
+                    span.shrink_to_hi().with_hi(full_span.hi()),
+                    msg,
+                    " { .. }".to_string(),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+
         if let Some(hir_field) = hir_fields.last() {
             self.suggest_fru_from_range_and_emit(hir_field, variant, args, err);
         } else {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index be6d9570e35..e26c09e3601 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1433,7 +1433,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // in a reentrant borrow, causing an ICE.
             let result = self
                 .at(&self.misc(sp), self.param_env)
-                .structurally_normalize(ty, &mut **self.fulfillment_cx.borrow_mut());
+                .structurally_normalize_ty(ty, &mut **self.fulfillment_cx.borrow_mut());
             match result {
                 Ok(normalized_ty) => normalized_ty,
                 Err(errors) => {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 46eed2db236..8e78fb3e219 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1210,7 +1210,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             // - foo((), "current", 42u32, "next")
                             // + foo((), 42u32)
                             {
-                                prev_extra_idx.map_or(true, |prev_extra_idx| {
+                                prev_extra_idx.is_none_or(|prev_extra_idx| {
                                     prev_extra_idx + 1 == arg_idx.index()
                                 })
                             }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 53e055fdeef..16294970f05 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -1143,7 +1143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.may_coerce(found, ty)
             }
             hir::FnRetTy::DefaultReturn(_) if in_closure => {
-                self.ret_coercion.as_ref().map_or(false, |ret| {
+                self.ret_coercion.as_ref().is_some_and(|ret| {
                     let ret_ty = ret.borrow().expected_ty();
                     self.may_coerce(found, ret_ty)
                 })
@@ -1784,14 +1784,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let results = self.typeck_results.borrow();
         // First, look for a `Clone::clone` call
         if segment.ident.name == sym::clone
-            && results.type_dependent_def_id(expr.hir_id).map_or(
-                false,
-                |did| {
+            && results.type_dependent_def_id(expr.hir_id).is_some_and(|did| {
                     let assoc_item = self.tcx.associated_item(did);
                     assoc_item.container == ty::AssocItemContainer::Trait
                         && assoc_item.container_id(self.tcx) == clone_trait_did
-                },
-            )
+                })
             // If that clone call hasn't already dereferenced the self type (i.e. don't give this
             // diagnostic in cases where we have `(&&T).clone()` and we expect `T`).
             && !results.expr_adjustments(callee_expr).iter().any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(..)))
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index cb21961f36b..9cd9ca040ce 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -87,7 +87,7 @@ fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet<LocalDef
 }
 
 fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> {
-    typeck_with_fallback(tcx, def_id, None)
+    typeck_with_inspect(tcx, def_id, None)
 }
 
 /// Same as `typeck` but `inspect` is invoked on evaluation of each root obligation.
@@ -99,11 +99,11 @@ pub fn inspect_typeck<'tcx>(
     def_id: LocalDefId,
     inspect: ObligationInspector<'tcx>,
 ) -> &'tcx ty::TypeckResults<'tcx> {
-    typeck_with_fallback(tcx, def_id, Some(inspect))
+    typeck_with_inspect(tcx, def_id, Some(inspect))
 }
 
 #[instrument(level = "debug", skip(tcx, inspector), ret)]
-fn typeck_with_fallback<'tcx>(
+fn typeck_with_inspect<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: LocalDefId,
     inspector: Option<ObligationInspector<'tcx>>,
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 116765325a9..b9d1f93bfb8 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -1,6 +1,5 @@
 use std::cell::{Cell, RefCell};
 use std::cmp::max;
-use std::iter;
 use std::ops::Deref;
 
 use rustc_data_structures::fx::FxHashSet;
@@ -1009,11 +1008,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
 
         if self.tcx.is_trait_alias(trait_def_id) {
             // For trait aliases, recursively assume all explicitly named traits are relevant
-            for expansion in traits::expand_trait_aliases(
-                self.tcx,
-                iter::once((ty::Binder::dummy(trait_ref), self.span)),
-            ) {
-                let bound_trait_ref = expansion.trait_ref();
+            for (bound_trait_pred, _) in
+                traits::expand_trait_aliases(self.tcx, [(trait_ref.upcast(self.tcx), self.span)]).0
+            {
+                assert_eq!(bound_trait_pred.polarity(), ty::PredicatePolarity::Positive);
+                let bound_trait_ref = bound_trait_pred.map_bound(|pred| pred.trait_ref);
                 for item in self.impl_or_trait_item(bound_trait_ref.def_id()) {
                     if !self.has_applicable_self(&item) {
                         self.record_static_candidate(CandidateSource::Trait(
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index b3d87ef4ad2..89843da9d7b 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -3761,18 +3761,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                         hir::TraitFn::Required([ident, ..]) => {
                                             ident.name == kw::SelfLower
                                         }
-                                        hir::TraitFn::Provided(body_id) => {
-                                            self.tcx.hir().body(*body_id).params.first().map_or(
-                                                false,
-                                                |param| {
-                                                    matches!(
-                                                        param.pat.kind,
-                                                        hir::PatKind::Binding(_, _, ident, _)
-                                                            if ident.name == kw::SelfLower
-                                                    )
-                                                },
-                                            )
-                                        }
+                                        hir::TraitFn::Provided(body_id) => self
+                                            .tcx
+                                            .hir()
+                                            .body(*body_id)
+                                            .params
+                                            .first()
+                                            .is_some_and(|param| {
+                                                matches!(
+                                                    param.pat.kind,
+                                                    hir::PatKind::Binding(_, _, ident, _)
+                                                        if ident.name == kw::SelfLower
+                                                )
+                                            }),
                                         _ => false,
                                     };
 
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 36094657eaf..cbd1db2ca25 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -21,6 +21,7 @@ use rustc_middle::{bug, span_bug};
 use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
 use rustc_session::parse::feature_err;
 use rustc_span::edit_distance::find_best_match_for_name;
+use rustc_span::edition::Edition;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::source_map::Spanned;
 use rustc_span::{BytePos, DUMMY_SP, Ident, Span, kw, sym};
@@ -169,15 +170,16 @@ enum AdjustMode {
     Pass,
 }
 
-/// `ref mut` patterns (explicit or match-ergonomics)
-/// are not allowed behind an `&` reference.
+/// `ref mut` bindings (explicit or match-ergonomics) are not allowed behind an `&` reference.
+/// Normally, the borrow checker enforces this, but for (currently experimental) match ergonomics,
+/// we track this when typing patterns for two purposes:
 ///
-/// This includes explicit `ref mut` behind `&` patterns
-/// that match against `&mut` references,
-/// where the code would have compiled
-/// had the pattern been written as `&mut`.
-/// However, the borrow checker will not catch
-/// this last case, so we need to throw an error ourselves.
+/// - For RFC 3627's Rule 3, when this would prevent us from binding with `ref mut`, we limit the
+///   default binding mode to be by shared `ref` when it would otherwise be `ref mut`.
+///
+/// - For RFC 3627's Rule 5, we allow `&` patterns to match against `&mut` references, treating them
+///   as if they were shared references. Since the scrutinee is mutable in this case, the borrow
+///   checker won't catch if we bind with `ref mut`, so we need to throw an error ourselves.
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 enum MutblCap {
     /// Mutability restricted to immutable.
@@ -213,7 +215,67 @@ impl MutblCap {
     }
 }
 
+/// Variations on RFC 3627's Rule 4: when do reference patterns match against inherited references?
+///
+/// "Inherited reference" designates the `&`/`&mut` types that arise from using match ergonomics, i.e.
+/// from matching a reference type with a non-reference pattern. E.g. when `Some(x)` matches on
+/// `&mut Option<&T>`, `x` gets type `&mut &T` and the outer `&mut` is considered "inherited".
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+enum InheritedRefMatchRule {
+    /// Reference patterns consume only the inherited reference if possible, regardless of whether
+    /// the underlying type being matched against is a reference type. If there is no inherited
+    /// reference, a reference will be consumed from the underlying type.
+    EatOuter,
+    /// Reference patterns consume only a reference from the underlying type if possible. If the
+    /// underlying type is not a reference type, the inherited reference will be consumed.
+    EatInner,
+    /// When the underlying type is a reference type, reference patterns consume both layers of
+    /// reference, i.e. they both reset the binding mode and consume the reference type. Reference
+    /// patterns are not permitted when there is no underlying reference type, i.e. they can't eat
+    /// only an inherited reference. This is the current stable Rust behavior.
+    EatBoth,
+}
+
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    /// Experimental pattern feature: after matching against a shared reference, do we limit the
+    /// default binding mode in subpatterns to be `ref` when it would otherwise be `ref mut`?
+    /// This corresponds to Rule 3 of RFC 3627.
+    fn downgrade_mut_inside_shared(&self) -> bool {
+        // NB: RFC 3627 proposes stabilizing Rule 3 in all editions. If we adopt the same behavior
+        // across all editions, this may be removed.
+        self.tcx.features().ref_pat_eat_one_layer_2024()
+            || self.tcx.features().ref_pat_eat_one_layer_2024_structural()
+    }
+
+    /// Experimental pattern feature: when do reference patterns match against inherited references?
+    /// This corresponds to variations on Rule 4 of RFC 3627.
+    fn ref_pat_matches_inherited_ref(&self, edition: Edition) -> InheritedRefMatchRule {
+        // NB: The particular rule used here is likely to differ across editions, so calls to this
+        // may need to become edition checks after match ergonomics stabilize.
+        if edition.at_least_rust_2024() {
+            if self.tcx.features().ref_pat_eat_one_layer_2024() {
+                InheritedRefMatchRule::EatOuter
+            } else if self.tcx.features().ref_pat_eat_one_layer_2024_structural() {
+                InheritedRefMatchRule::EatInner
+            } else {
+                // Currently, matching against an inherited ref on edition 2024 is an error.
+                // Use `EatBoth` as a fallback to be similar to stable Rust.
+                InheritedRefMatchRule::EatBoth
+            }
+        } else {
+            InheritedRefMatchRule::EatBoth
+        }
+    }
+
+    /// Experimental pattern feature: do `&` patterns match against `&mut` references, treating them
+    /// as if they were shared references? This corresponds to Rule 5 of RFC 3627.
+    fn ref_pat_matches_mut_ref(&self) -> bool {
+        // NB: RFC 3627 proposes stabilizing Rule 5 in all editions. If we adopt the same behavior
+        // across all editions, this may be removed.
+        self.tcx.features().ref_pat_eat_one_layer_2024()
+            || self.tcx.features().ref_pat_eat_one_layer_2024_structural()
+    }
+
     /// Type check the given top level pattern against the `expected` type.
     ///
     /// If a `Some(span)` is provided and `origin_expr` holds,
@@ -474,13 +536,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             });
         }
 
-        let features = self.tcx.features();
-        if features.ref_pat_eat_one_layer_2024() || features.ref_pat_eat_one_layer_2024_structural()
-        {
+        if self.downgrade_mut_inside_shared() {
             def_br = def_br.cap_ref_mutability(max_ref_mutbl.as_mutbl());
-            if def_br == ByRef::Yes(Mutability::Not) {
-                max_ref_mutbl = MutblCap::Not;
-            }
+        }
+        if def_br == ByRef::Yes(Mutability::Not) {
+            max_ref_mutbl = MutblCap::Not;
         }
 
         if !pat_adjustments.is_empty() {
@@ -731,6 +791,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // Determine the binding mode...
         let bm = match user_bind_annot {
             BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => {
+                // Only mention the experimental `mut_ref` feature if if we're in edition 2024 and
+                // using other experimental matching features compatible with it.
                 if pat.span.at_least_rust_2024()
                     && (self.tcx.features().ref_pat_eat_one_layer_2024()
                         || self.tcx.features().ref_pat_eat_one_layer_2024_structural())
@@ -2228,55 +2290,70 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         mut pat_info: PatInfo<'_, 'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
-        let features = tcx.features();
-        let ref_pat_eat_one_layer_2024 = features.ref_pat_eat_one_layer_2024();
-        let ref_pat_eat_one_layer_2024_structural =
-            features.ref_pat_eat_one_layer_2024_structural();
-
-        let no_ref_mut_behind_and =
-            ref_pat_eat_one_layer_2024 || ref_pat_eat_one_layer_2024_structural;
-        let new_match_ergonomics = pat.span.at_least_rust_2024() && no_ref_mut_behind_and;
 
         let pat_prefix_span =
             inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end));
 
-        if no_ref_mut_behind_and {
-            if pat_mutbl == Mutability::Not {
-                // Prevent the inner pattern from binding with `ref mut`.
-                pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(pat_prefix_span);
-            }
-        } else {
-            pat_info.max_ref_mutbl = MutblCap::Mut;
+        let ref_pat_matches_mut_ref = self.ref_pat_matches_mut_ref();
+        if ref_pat_matches_mut_ref && pat_mutbl == Mutability::Not {
+            // If `&` patterns can match against mutable reference types (RFC 3627, Rule 5), we need
+            // to prevent subpatterns from binding with `ref mut`. Subpatterns of a shared reference
+            // pattern should have read-only access to the scrutinee, and the borrow checker won't
+            // catch it in this case.
+            pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(pat_prefix_span);
         }
 
         expected = self.try_structurally_resolve_type(pat.span, expected);
-        if new_match_ergonomics {
-            if let ByRef::Yes(inh_mut) = pat_info.binding_mode {
-                if !ref_pat_eat_one_layer_2024 && let ty::Ref(_, _, r_mutbl) = *expected.kind() {
-                    // Don't attempt to consume inherited reference
-                    pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(r_mutbl);
-                } else {
+        // Determine whether we're consuming an inherited reference and resetting the default
+        // binding mode, based on edition and enabled experimental features.
+        if let ByRef::Yes(inh_mut) = pat_info.binding_mode {
+            match self.ref_pat_matches_inherited_ref(pat.span.edition()) {
+                InheritedRefMatchRule::EatOuter => {
                     // ref pattern attempts to consume inherited reference
                     if pat_mutbl > inh_mut {
                         // Tried to match inherited `ref` with `&mut`
-                        if !ref_pat_eat_one_layer_2024_structural {
-                            let err_msg = "mismatched types";
-                            let err = if let Some(span) = pat_prefix_span {
-                                let mut err = self.dcx().struct_span_err(span, err_msg);
-                                err.code(E0308);
-                                err.note("cannot match inherited `&` with `&mut` pattern");
-                                err.span_suggestion_verbose(
-                                    span,
-                                    "replace this `&mut` pattern with `&`",
-                                    "&",
-                                    Applicability::MachineApplicable,
-                                );
-                                err
-                            } else {
-                                self.dcx().struct_span_err(pat.span, err_msg)
-                            };
-                            err.emit();
+                        // NB: This assumes that `&` patterns can match against mutable references
+                        // (RFC 3627, Rule 5). If we implement a pattern typing ruleset with Rule 4E
+                        // but not Rule 5, we'll need to check that here.
+                        debug_assert!(ref_pat_matches_mut_ref);
+                        let err_msg = "mismatched types";
+                        let err = if let Some(span) = pat_prefix_span {
+                            let mut err = self.dcx().struct_span_err(span, err_msg);
+                            err.code(E0308);
+                            err.note("cannot match inherited `&` with `&mut` pattern");
+                            err.span_suggestion_verbose(
+                                span,
+                                "replace this `&mut` pattern with `&`",
+                                "&",
+                                Applicability::MachineApplicable,
+                            );
+                            err
+                        } else {
+                            self.dcx().struct_span_err(pat.span, err_msg)
+                        };
+                        err.emit();
+                    }
 
+                    pat_info.binding_mode = ByRef::No;
+                    self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
+                    self.check_pat(inner, expected, pat_info);
+                    return expected;
+                }
+                InheritedRefMatchRule::EatInner => {
+                    if let ty::Ref(_, _, r_mutbl) = *expected.kind() {
+                        // Match against the reference type; don't consume the inherited ref.
+                        pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(r_mutbl);
+                    } else {
+                        // The expected type isn't a reference, so match against the inherited ref.
+                        if pat_mutbl > inh_mut {
+                            // We can't match an inherited shared reference with `&mut`. This will
+                            // be a type error later, since we're matching a reference pattern
+                            // against a non-reference type.
+                            // NB: This assumes that `&` patterns can match against mutable
+                            // references (RFC 3627, Rule 5). If we implement a pattern typing
+                            // ruleset with Rule 4 but not Rule 5, we'll need to check that here.
+                            debug_assert!(ref_pat_matches_mut_ref);
+                        } else {
                             pat_info.binding_mode = ByRef::No;
                             self.typeck_results
                                 .borrow_mut()
@@ -2285,24 +2362,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             self.check_pat(inner, expected, pat_info);
                             return expected;
                         }
-                    } else {
-                        pat_info.binding_mode = ByRef::No;
-                        self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
-                        self.check_pat(inner, expected, pat_info);
-                        return expected;
                     }
                 }
-            }
-        } else {
-            // Reset binding mode on old editions
-            if pat_info.binding_mode != ByRef::No {
-                pat_info.binding_mode = ByRef::No;
-                self.add_rust_2024_migration_desugared_pat(
-                    pat_info.top_info.hir_id,
-                    pat.span,
-                    inner.span,
-                    "cannot implicitly match against multiple layers of reference",
-                )
+                InheritedRefMatchRule::EatBoth => {
+                    // Reset binding mode on old editions
+                    pat_info.binding_mode = ByRef::No;
+                    self.add_rust_2024_migration_desugared_pat(
+                        pat_info.top_info.hir_id,
+                        pat.span,
+                        inner.span,
+                        "cannot implicitly match against multiple layers of reference",
+                    )
+                }
             }
         }
 
@@ -2317,10 +2388,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 debug!("check_pat_ref: expected={:?}", expected);
                 match *expected.kind() {
                     ty::Ref(_, r_ty, r_mutbl)
-                        if (no_ref_mut_behind_and && r_mutbl >= pat_mutbl)
+                        if (ref_pat_matches_mut_ref && r_mutbl >= pat_mutbl)
                             || r_mutbl == pat_mutbl =>
                     {
-                        if no_ref_mut_behind_and && r_mutbl == Mutability::Not {
+                        if r_mutbl == Mutability::Not {
                             pat_info.max_ref_mutbl = MutblCap::Not;
                         }
 
diff --git a/compiler/rustc_index/src/interval.rs b/compiler/rustc_index/src/interval.rs
index 34f541a8cc6..a3d87f59567 100644
--- a/compiler/rustc_index/src/interval.rs
+++ b/compiler/rustc_index/src/interval.rs
@@ -258,7 +258,7 @@ impl<I: Idx> IntervalSet<I> {
             }
             current = Some(*end);
         }
-        current.map_or(true, |x| x < self.domain as u32)
+        current.is_none_or(|x| x < self.domain as u32)
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs
index 5fc9b679c8a..69ab0e69e21 100644
--- a/compiler/rustc_infer/src/infer/context.rs
+++ b/compiler/rustc_infer/src/infer/context.rs
@@ -114,7 +114,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
         )
     }
 
-    fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>> + Copy, U>(
+    fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>>, U>(
         &self,
         value: ty::Binder<'tcx, T>,
         f: impl FnOnce(T) -> U,
diff --git a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs
index 7908733e734..061f7e6c22a 100644
--- a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs
+++ b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs
@@ -24,9 +24,9 @@ impl<'tcx> InferCtxt<'tcx> {
     #[instrument(level = "debug", skip(self), ret)]
     pub fn enter_forall_and_leak_universe<T>(&self, binder: ty::Binder<'tcx, T>) -> T
     where
-        T: TypeFoldable<TyCtxt<'tcx>> + Copy,
+        T: TypeFoldable<TyCtxt<'tcx>>,
     {
-        if let Some(inner) = binder.no_bound_vars() {
+        if let Some(inner) = binder.clone().no_bound_vars() {
             return inner;
         }
 
@@ -71,7 +71,7 @@ impl<'tcx> InferCtxt<'tcx> {
     #[instrument(level = "debug", skip(self, f))]
     pub fn enter_forall<T, U>(&self, forall: ty::Binder<'tcx, T>, f: impl FnOnce(T) -> U) -> U
     where
-        T: TypeFoldable<TyCtxt<'tcx>> + Copy,
+        T: TypeFoldable<TyCtxt<'tcx>>,
     {
         // FIXME: currently we do nothing to prevent placeholders with the new universe being
         // used after exiting `f`. For example region subtyping can result in outlives constraints
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index ab8ada1596c..66ed49fe326 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -1,5 +1,5 @@
 use rustc_data_structures::fx::FxHashSet;
-use rustc_middle::ty::{self, ToPolyTraitRef, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::{Ident, Span};
 pub use rustc_type_ir::elaborate::*;
 
@@ -125,8 +125,8 @@ pub fn transitive_bounds_that_define_assoc_item<'tcx>(
                     .iter_identity_copied()
                     .map(|(clause, _)| clause.instantiate_supertrait(tcx, trait_ref))
                     .filter_map(|clause| clause.as_trait_clause())
-                    // FIXME: Negative supertraits are elaborated here lol
-                    .map(|trait_pred| trait_pred.to_poly_trait_ref()),
+                    .filter(|clause| clause.polarity() == ty::PredicatePolarity::Positive)
+                    .map(|clause| clause.map_bound(|clause| clause.trait_ref)),
             );
 
             return Some(trait_ref);
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 1456255ea14..2113345eda3 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -1,6 +1,5 @@
 use std::path::PathBuf;
 use std::result;
-use std::sync::Arc;
 
 use rustc_ast::{LitKind, MetaItemKind, token};
 use rustc_codegen_ssa::traits::CodegenBackend;
@@ -309,6 +308,11 @@ pub struct Config {
     pub output_dir: Option<PathBuf>,
     pub output_file: Option<OutFileName>,
     pub ice_file: Option<PathBuf>,
+    /// Load files from sources other than the file system.
+    ///
+    /// Has no uses within this repository, but may be used in the future by
+    /// bjorn3 for "hooking rust-analyzer's VFS into rustc at some point for
+    /// running rustc without having to save". (See #102759.)
     pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
     /// The list of fluent resources, used for lints declared with
     /// [`Diagnostic`](rustc_errors::Diagnostic) and [`LintDiagnostic`](rustc_errors::LintDiagnostic).
@@ -337,6 +341,11 @@ pub struct Config {
     pub override_queries: Option<fn(&Session, &mut Providers)>,
 
     /// This is a callback from the driver that is called to create a codegen backend.
+    ///
+    /// Has no uses within this repository, but is used by bjorn3 for "the
+    /// hotswapping branch of cg_clif" for "setting the codegen backend from a
+    /// custom driver where the custom codegen backend has arbitrary data."
+    /// (See #102759.)
     pub make_codegen_backend:
         Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,
 
@@ -346,8 +355,7 @@ pub struct Config {
     /// The inner atomic value is set to true when a feature marked as `internal` is
     /// enabled. Makes it so that "please report a bug" is hidden, as ICEs with
     /// internal features are wontfix, and they are usually the cause of the ICEs.
-    /// None signifies that this is not tracked.
-    pub using_internal_features: Arc<std::sync::atomic::AtomicBool>,
+    pub using_internal_features: &'static std::sync::atomic::AtomicBool,
 
     /// 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
@@ -383,7 +391,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
     crate::callbacks::setup_callbacks();
 
     let sysroot = filesearch::materialize_sysroot(config.opts.maybe_sysroot.clone());
-    let target = config::build_target_config(&early_dcx, &config.opts, &sysroot);
+    let target = config::build_target_config(&early_dcx, &config.opts.target_triple, &sysroot);
     let file_loader = config.file_loader.unwrap_or_else(|| Box::new(RealFileLoader));
     let path_mapping = config.opts.file_path_mapping();
     let hash_kind = config.opts.unstable_opts.src_hash_algorithm(&target);
@@ -533,7 +541,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
 
 pub fn try_print_query_stack(
     dcx: DiagCtxtHandle<'_>,
-    num_frames: Option<usize>,
+    limit_frames: Option<usize>,
     file: Option<std::fs::File>,
 ) {
     eprintln!("query stack during panic:");
@@ -541,13 +549,13 @@ pub fn try_print_query_stack(
     // Be careful relying on global state here: this code is called from
     // a panic hook, which means that the global `DiagCtxt` may be in a weird
     // state if it was responsible for triggering the panic.
-    let i = ty::tls::with_context_opt(|icx| {
+    let all_frames = ty::tls::with_context_opt(|icx| {
         if let Some(icx) = icx {
             ty::print::with_no_queries!(print_query_stack(
                 QueryCtxt::new(icx.tcx),
                 icx.query,
                 dcx,
-                num_frames,
+                limit_frames,
                 file,
             ))
         } else {
@@ -555,9 +563,14 @@ pub fn try_print_query_stack(
         }
     });
 
-    if num_frames == None || num_frames >= Some(i) {
-        eprintln!("end of query stack");
+    if let Some(limit_frames) = limit_frames
+        && all_frames > limit_frames
+    {
+        eprintln!(
+            "... and {} other queries... use `env RUST_BACKTRACE=1` to see the full query stack",
+            all_frames - limit_frames
+        );
     } else {
-        eprintln!("we're just showing a limited slice of the query stack");
+        eprintln!("end of query stack");
     }
 }
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index aff66e48fbb..241bc35857a 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -875,6 +875,8 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
     });
     // Freeze definitions as we don't add new ones at this point.
     // We need to wait until now since we synthesize a by-move body
+    // for all coroutine-closures.
+    //
     // This improves performance by allowing lock-free access to them.
     tcx.untracked().definitions.freeze();
 
@@ -887,7 +889,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
         });
     });
     sess.time("MIR_effect_checking", || {
-        for def_id in tcx.hir().body_owners() {
+        tcx.hir().par_body_owners(|def_id| {
             tcx.ensure().has_ffi_unwind_calls(def_id);
 
             // If we need to codegen, ensure that we emit all errors from
@@ -898,15 +900,17 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
             {
                 tcx.ensure().mir_drops_elaborated_and_const_checked(def_id);
             }
-        }
+        });
     });
-    tcx.hir().par_body_owners(|def_id| {
-        if tcx.is_coroutine(def_id.to_def_id()) {
-            tcx.ensure().mir_coroutine_witnesses(def_id);
-            tcx.ensure().check_coroutine_obligations(
-                tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(),
-            );
-        }
+    sess.time("coroutine_obligations", || {
+        tcx.hir().par_body_owners(|def_id| {
+            if tcx.is_coroutine(def_id.to_def_id()) {
+                tcx.ensure().mir_coroutine_witnesses(def_id);
+                tcx.ensure().check_coroutine_obligations(
+                    tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(),
+                );
+            }
+        });
     });
 
     sess.time("layout_testing", || layout_test::test_layout(tcx));
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 07c4b898721..74d02ac2227 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -2,7 +2,7 @@
 use std::collections::{BTreeMap, BTreeSet};
 use std::num::NonZero;
 use std::path::{Path, PathBuf};
-use std::sync::Arc;
+use std::sync::atomic::AtomicBool;
 
 use rustc_data_structures::profiling::TimePassesFormat;
 use rustc_errors::emitter::HumanReadableErrorType;
@@ -42,7 +42,8 @@ where
     let matches = optgroups().parse(args).unwrap();
     let sessopts = build_session_options(&mut early_dcx, &matches);
     let sysroot = filesearch::materialize_sysroot(sessopts.maybe_sysroot.clone());
-    let target = rustc_session::config::build_target_config(&early_dcx, &sessopts, &sysroot);
+    let target =
+        rustc_session::config::build_target_config(&early_dcx, &sessopts.target_triple, &sysroot);
     let hash_kind = sessopts.unstable_opts.src_hash_algorithm(&target);
     let checksum_hash_kind = sessopts.unstable_opts.checksum_hash_algorithm();
     let sm_inputs = Some(SourceMapInputs {
@@ -61,6 +62,8 @@ where
             temps_dir,
         };
 
+        static USING_INTERNAL_FEATURES: AtomicBool = AtomicBool::new(false);
+
         let sess = build_session(
             early_dcx,
             sessopts,
@@ -73,7 +76,7 @@ where
             sysroot,
             "",
             None,
-            Arc::default(),
+            &USING_INTERNAL_FEATURES,
             Default::default(),
         );
         let cfg = parse_cfg(sess.dcx(), matches.opt_strs("cfg"));
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 7522e21d0ef..64c8f00cc83 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -209,7 +209,9 @@ lint_dangling_pointers_from_temporaries = a dangling pointer will be produced be
     .label_ptr = this pointer will immediately be invalid
     .label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
     .note = pointers do not have a lifetime; when calling `{$callee}` the `{$ty}` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
-    .help = for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+    .help_bind = you must make sure that the variable you bind the `{$ty}` to lives at least as long as the pointer returned by the call to `{$callee}`
+    .help_returned = in particular, if this pointer is returned from the current function, binding the `{$ty}` inside the function will not suffice
+    .help_visit = for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance
     .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary
@@ -970,6 +972,8 @@ lint_unused_result = unused result of type `{$ty}`
 
 lint_use_let_underscore_ignore_suggestion = use `let _ = ...` to ignore the expression or result
 
+lint_uses_power_alignment = repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+
 lint_variant_size_differences =
     enum variant is more than three times larger ({$largest} bytes) than the next largest
 
diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs
index 289e2c9b722..ef79f1301e5 100644
--- a/compiler/rustc_lint/src/expect.rs
+++ b/compiler/rustc_lint/src/expect.rs
@@ -57,7 +57,7 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
         let expect_id = canonicalize_id(expect_id);
 
         if !fulfilled_expectations.contains(&expect_id)
-            && tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter))
+            && tool_filter.is_none_or(|filter| expectation.lint_tool == Some(filter))
         {
             let rationale = expectation.reason.map(|rationale| ExpectationNote { rationale });
             let note = expectation.is_unfulfilled_lint_expectations;
diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs
index 259ea908fc6..b5a6159bd0a 100644
--- a/compiler/rustc_lint/src/if_let_rescope.rs
+++ b/compiler/rustc_lint/src/if_let_rescope.rs
@@ -9,7 +9,7 @@ use rustc_errors::{
 use rustc_hir::{self as hir, HirIdSet};
 use rustc_macros::LintDiagnostic;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::lint::{FutureIncompatibilityReason, Level};
+use rustc_session::lint::{FutureIncompatibilityReason, LintId};
 use rustc_session::{declare_lint, impl_lint_pass};
 use rustc_span::Span;
 use rustc_span::edition::Edition;
@@ -245,12 +245,12 @@ impl_lint_pass!(
 
 impl<'tcx> LateLintPass<'tcx> for IfLetRescope {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
-        if expr.span.edition().at_least_rust_2024() {
-            return;
-        }
-        if let (Level::Allow, _) = cx.tcx.lint_level_at_node(IF_LET_RESCOPE, expr.hir_id) {
+        if expr.span.edition().at_least_rust_2024()
+            || cx.tcx.lints_that_dont_need_to_run(()).contains(&LintId::of(IF_LET_RESCOPE))
+        {
             return;
         }
+
         if let hir::ExprKind::Loop(block, _label, hir::LoopSource::While, _span) = expr.kind
             && let Some(value) = block.expr
             && let hir::ExprKind::If(cond, _conseq, _alt) = value.kind
@@ -290,7 +290,6 @@ struct IfLetRescopeLint {
     rewrite: Option<IfLetRescopeRewrite>,
 }
 
-// #[derive(Subdiagnostic)]
 struct IfLetRescopeRewrite {
     match_heads: Vec<SingleArmMatchBegin>,
     consequent_heads: Vec<ConsequentRewrite>,
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index ac995b59caf..2f610802ff5 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1139,7 +1139,9 @@ pub(crate) struct IgnoredUnlessCrateSpecified<'a> {
 #[derive(LintDiagnostic)]
 #[diag(lint_dangling_pointers_from_temporaries)]
 #[note]
-#[help]
+#[help(lint_help_bind)]
+#[help(lint_help_returned)]
+#[help(lint_help_visit)]
 // FIXME: put #[primary_span] on `ptr_span` once it does not cause conflicts
 pub(crate) struct DanglingPointersFromTemporaries<'tcx> {
     pub callee: Symbol,
@@ -1693,6 +1695,10 @@ pub(crate) struct OverflowingLiteral<'a> {
 }
 
 #[derive(LintDiagnostic)]
+#[diag(lint_uses_power_alignment)]
+pub(crate) struct UsesPowerAlignment;
+
+#[derive(LintDiagnostic)]
 #[diag(lint_unused_comparisons)]
 pub(crate) struct UnusedComparisons;
 
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 3bd27a224e7..0757e6840c6 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1,14 +1,15 @@
 use std::iter;
 use std::ops::ControlFlow;
 
-use rustc_abi::{BackendRepr, ExternAbi, TagEncoding, Variants, WrappingRange};
+use rustc_abi::{BackendRepr, ExternAbi, TagEncoding, VariantIdx, Variants, WrappingRange};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::DiagMessage;
 use rustc_hir::{Expr, ExprKind, LangItem};
 use rustc_middle::bug;
 use rustc_middle::ty::layout::{LayoutOf, SizeSkeleton};
 use rustc_middle::ty::{
-    self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
+    self, Adt, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
+    TypeVisitableExt,
 };
 use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
 use rustc_span::def_id::LocalDefId;
@@ -23,7 +24,7 @@ use crate::lints::{
     AmbiguousWidePointerComparisonsAddrSuggestion, AtomicOrderingFence, AtomicOrderingLoad,
     AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons,
     InvalidNanComparisonsSuggestion, UnpredictableFunctionPointerComparisons,
-    UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons,
+    UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons, UsesPowerAlignment,
     VariantSizeDifferencesDiag,
 };
 use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
@@ -727,7 +728,60 @@ declare_lint! {
     "proper use of libc types in foreign item definitions"
 }
 
-declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS]);
+declare_lint! {
+    /// The `uses_power_alignment` lint detects specific `repr(C)`
+    /// aggregates on AIX.
+    /// In its platform C ABI, AIX uses the "power" (as in PowerPC) alignment
+    /// rule (detailed in https://www.ibm.com/docs/en/xl-c-and-cpp-aix/16.1?topic=data-using-alignment-modes#alignment),
+    /// which can also be set for XLC by `#pragma align(power)` or
+    /// `-qalign=power`. Aggregates with a floating-point type as the
+    /// recursively first field (as in "at offset 0") modify the layout of
+    /// *subsequent* fields of the associated structs to use an alignment value
+    /// where the floating-point type is aligned on a 4-byte boundary.
+    ///
+    /// The power alignment rule for structs needed for C compatibility is
+    /// unimplementable within `repr(C)` in the compiler without building in
+    /// handling of references to packed fields and infectious nested layouts,
+    /// so a warning is produced in these situations.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (fails on non-powerpc64-ibm-aix)
+    /// #[repr(C)]
+    /// pub struct Floats {
+    ///     a: f64,
+    ///     b: u8,
+    ///     c: f64,
+    /// }
+    /// ```
+    ///
+    /// This will produce:
+    ///
+    /// ```text
+    /// warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+    ///  --> <source>:5:3
+    ///   |
+    /// 5 |   c: f64,
+    ///   |   ^^^^^^
+    ///   |
+    ///   = note: `#[warn(uses_power_alignment)]` on by default
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// The power alignment rule specifies that the above struct has the
+    /// following alignment:
+    ///  - offset_of!(Floats, a) == 0
+    ///  - offset_of!(Floats, b) == 8
+    ///  - offset_of!(Floats, c) == 12
+    /// However, rust currently aligns `c` at offset_of!(Floats, c) == 16.
+    /// Thus, a warning should be produced for the above struct in this case.
+    USES_POWER_ALIGNMENT,
+    Warn,
+    "Structs do not follow the power alignment rule under repr(C)"
+}
+
+declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS, USES_POWER_ALIGNMENT]);
 
 #[derive(Clone, Copy)]
 pub(crate) enum CItemKind {
@@ -1539,6 +1593,71 @@ impl ImproperCTypesDefinitions {
             vis.check_type_for_ffi_and_report_errors(span, fn_ptr_ty, true, false);
         }
     }
+
+    fn check_arg_for_power_alignment<'tcx>(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> bool {
+        // Structs (under repr(C)) follow the power alignment rule if:
+        //   - the first field of the struct is a floating-point type that
+        //     is greater than 4-bytes, or
+        //   - the first field of the struct is an aggregate whose
+        //     recursively first field is a floating-point type greater than
+        //     4 bytes.
+        if cx.tcx.sess.target.os != "aix" {
+            return false;
+        }
+        if ty.is_floating_point() && ty.primitive_size(cx.tcx).bytes() > 4 {
+            return true;
+        } else if let Adt(adt_def, _) = ty.kind()
+            && adt_def.is_struct()
+        {
+            let struct_variant = adt_def.variant(VariantIdx::ZERO);
+            // Within a nested struct, all fields are examined to correctly
+            // report if any fields after the nested struct within the
+            // original struct are misaligned.
+            for struct_field in &struct_variant.fields {
+                let field_ty = cx.tcx.type_of(struct_field.did).instantiate_identity();
+                if self.check_arg_for_power_alignment(cx, field_ty) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    fn check_struct_for_power_alignment<'tcx>(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        item: &'tcx hir::Item<'tcx>,
+    ) {
+        let adt_def = cx.tcx.adt_def(item.owner_id.to_def_id());
+        if adt_def.repr().c()
+            && !adt_def.repr().packed()
+            && cx.tcx.sess.target.os == "aix"
+            && !adt_def.all_fields().next().is_none()
+        {
+            let struct_variant_data = item.expect_struct().0;
+            for (index, ..) in struct_variant_data.fields().iter().enumerate() {
+                // Struct fields (after the first field) are checked for the
+                // power alignment rule, as fields after the first are likely
+                // to be the fields that are misaligned.
+                if index != 0 {
+                    let first_field_def = struct_variant_data.fields()[index];
+                    let def_id = first_field_def.def_id;
+                    let ty = cx.tcx.type_of(def_id).instantiate_identity();
+                    if self.check_arg_for_power_alignment(cx, ty) {
+                        cx.emit_span_lint(
+                            USES_POWER_ALIGNMENT,
+                            first_field_def.span,
+                            UsesPowerAlignment,
+                        );
+                    }
+                }
+            }
+        }
+    }
 }
 
 /// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
@@ -1562,8 +1681,13 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
             }
             // See `check_fn`..
             hir::ItemKind::Fn { .. } => {}
+            // Structs are checked based on if they follow the power alignment
+            // rule (under repr(C)).
+            hir::ItemKind::Struct(..) => {
+                self.check_struct_for_power_alignment(cx, item);
+            }
             // See `check_field_def`..
-            hir::ItemKind::Union(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) => {}
+            hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) => {}
             // Doesn't define something that can contain a external type to be checked.
             hir::ItemKind::Impl(..)
             | hir::ItemKind::TraitAlias(..)
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index dd72ea2497f..35186778671 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -2,6 +2,7 @@
 
 #include "llvm-c/Analysis.h"
 #include "llvm-c/Core.h"
+#include "llvm-c/DebugInfo.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Statistic.h"
@@ -676,120 +677,73 @@ template <typename DIT> DIT *unwrapDIPtr(LLVMMetadataRef Ref) {
 #define DIArray DINodeArray
 #define unwrapDI unwrapDIPtr
 
-// These values **must** match debuginfo::DIFlags! They also *happen*
-// to match LLVM, but that isn't required as we do giant sets of
-// matching below. The value shouldn't be directly passed to LLVM.
-enum class LLVMRustDIFlags : uint32_t {
-  FlagZero = 0,
-  FlagPrivate = 1,
-  FlagProtected = 2,
-  FlagPublic = 3,
-  FlagFwdDecl = (1 << 2),
-  FlagAppleBlock = (1 << 3),
-  FlagBlockByrefStruct = (1 << 4),
-  FlagVirtual = (1 << 5),
-  FlagArtificial = (1 << 6),
-  FlagExplicit = (1 << 7),
-  FlagPrototyped = (1 << 8),
-  FlagObjcClassComplete = (1 << 9),
-  FlagObjectPointer = (1 << 10),
-  FlagVector = (1 << 11),
-  FlagStaticMember = (1 << 12),
-  FlagLValueReference = (1 << 13),
-  FlagRValueReference = (1 << 14),
-  FlagExternalTypeRef = (1 << 15),
-  FlagIntroducedVirtual = (1 << 18),
-  FlagBitField = (1 << 19),
-  FlagNoReturn = (1 << 20),
-  // Do not add values that are not supported by the minimum LLVM
-  // version we support! see llvm/include/llvm/IR/DebugInfoFlags.def
-};
-
-inline LLVMRustDIFlags operator&(LLVMRustDIFlags A, LLVMRustDIFlags B) {
-  return static_cast<LLVMRustDIFlags>(static_cast<uint32_t>(A) &
-                                      static_cast<uint32_t>(B));
-}
-
-inline LLVMRustDIFlags operator|(LLVMRustDIFlags A, LLVMRustDIFlags B) {
-  return static_cast<LLVMRustDIFlags>(static_cast<uint32_t>(A) |
-                                      static_cast<uint32_t>(B));
-}
-
-inline LLVMRustDIFlags &operator|=(LLVMRustDIFlags &A, LLVMRustDIFlags B) {
-  return A = A | B;
-}
-
-inline bool isSet(LLVMRustDIFlags F) { return F != LLVMRustDIFlags::FlagZero; }
-
-inline LLVMRustDIFlags visibility(LLVMRustDIFlags F) {
-  return static_cast<LLVMRustDIFlags>(static_cast<uint32_t>(F) & 0x3);
-}
-
-static DINode::DIFlags fromRust(LLVMRustDIFlags Flags) {
-  DINode::DIFlags Result = DINode::DIFlags::FlagZero;
-
-  switch (visibility(Flags)) {
-  case LLVMRustDIFlags::FlagPrivate:
-    Result |= DINode::DIFlags::FlagPrivate;
-    break;
-  case LLVMRustDIFlags::FlagProtected:
-    Result |= DINode::DIFlags::FlagProtected;
-    break;
-  case LLVMRustDIFlags::FlagPublic:
-    Result |= DINode::DIFlags::FlagPublic;
-    break;
-  default:
-    // The rest are handled below
-    break;
-  }
-
-  if (isSet(Flags & LLVMRustDIFlags::FlagFwdDecl)) {
-    Result |= DINode::DIFlags::FlagFwdDecl;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagAppleBlock)) {
-    Result |= DINode::DIFlags::FlagAppleBlock;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagVirtual)) {
-    Result |= DINode::DIFlags::FlagVirtual;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagArtificial)) {
-    Result |= DINode::DIFlags::FlagArtificial;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagExplicit)) {
-    Result |= DINode::DIFlags::FlagExplicit;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagPrototyped)) {
-    Result |= DINode::DIFlags::FlagPrototyped;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagObjcClassComplete)) {
-    Result |= DINode::DIFlags::FlagObjcClassComplete;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagObjectPointer)) {
-    Result |= DINode::DIFlags::FlagObjectPointer;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagVector)) {
-    Result |= DINode::DIFlags::FlagVector;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagStaticMember)) {
-    Result |= DINode::DIFlags::FlagStaticMember;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagLValueReference)) {
-    Result |= DINode::DIFlags::FlagLValueReference;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagRValueReference)) {
-    Result |= DINode::DIFlags::FlagRValueReference;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagIntroducedVirtual)) {
-    Result |= DINode::DIFlags::FlagIntroducedVirtual;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagBitField)) {
-    Result |= DINode::DIFlags::FlagBitField;
-  }
-  if (isSet(Flags & LLVMRustDIFlags::FlagNoReturn)) {
-    Result |= DINode::DIFlags::FlagNoReturn;
-  }
-
-  return Result;
+// FIXME(Zalathar): This is a temporary typedef to avoid churning dozens of
+// bindings that are going to be deleted and replaced with their LLVM-C
+// equivalents, as part of #134009. After that happens, the remaining bindings
+// can be adjusted to use `LLVMDIFlags` instead of relying on this typedef.
+typedef LLVMDIFlags LLVMRustDIFlags;
+
+// Statically assert that `LLVMDIFlags` (C) and `DIFlags` (C++) have the same
+// layout, at least for the flags we know about. This isn't guaranteed, but is
+// likely to remain true, and as long as it is true it makes conversions easy.
+#define ASSERT_DIFLAG_VALUE(FLAG, VALUE)                                       \
+  static_assert((LLVMDI##FLAG == (VALUE)) && (DINode::DIFlags::FLAG == (VALUE)))
+ASSERT_DIFLAG_VALUE(FlagZero, 0);
+ASSERT_DIFLAG_VALUE(FlagPrivate, 1);
+ASSERT_DIFLAG_VALUE(FlagProtected, 2);
+ASSERT_DIFLAG_VALUE(FlagPublic, 3);
+// Bit (1 << 1) is part of the private/protected/public values above.
+ASSERT_DIFLAG_VALUE(FlagFwdDecl, 1 << 2);
+ASSERT_DIFLAG_VALUE(FlagAppleBlock, 1 << 3);
+ASSERT_DIFLAG_VALUE(FlagReservedBit4, 1 << 4);
+ASSERT_DIFLAG_VALUE(FlagVirtual, 1 << 5);
+ASSERT_DIFLAG_VALUE(FlagArtificial, 1 << 6);
+ASSERT_DIFLAG_VALUE(FlagExplicit, 1 << 7);
+ASSERT_DIFLAG_VALUE(FlagPrototyped, 1 << 8);
+ASSERT_DIFLAG_VALUE(FlagObjcClassComplete, 1 << 9);
+ASSERT_DIFLAG_VALUE(FlagObjectPointer, 1 << 10);
+ASSERT_DIFLAG_VALUE(FlagVector, 1 << 11);
+ASSERT_DIFLAG_VALUE(FlagStaticMember, 1 << 12);
+ASSERT_DIFLAG_VALUE(FlagLValueReference, 1 << 13);
+ASSERT_DIFLAG_VALUE(FlagRValueReference, 1 << 14);
+// Bit (1 << 15) has been recycled, but the C API value hasn't been renamed.
+static_assert((LLVMDIFlagReserved == (1 << 15)) &&
+              (DINode::DIFlags::FlagExportSymbols == (1 << 15)));
+ASSERT_DIFLAG_VALUE(FlagSingleInheritance, 1 << 16);
+ASSERT_DIFLAG_VALUE(FlagMultipleInheritance, 2 << 16);
+ASSERT_DIFLAG_VALUE(FlagVirtualInheritance, 3 << 16);
+// Bit (1 << 17) is part of the inheritance values above.
+ASSERT_DIFLAG_VALUE(FlagIntroducedVirtual, 1 << 18);
+ASSERT_DIFLAG_VALUE(FlagBitField, 1 << 19);
+ASSERT_DIFLAG_VALUE(FlagNoReturn, 1 << 20);
+// Bit (1 << 21) is unused, but was `LLVMDIFlagMainSubprogram`.
+ASSERT_DIFLAG_VALUE(FlagTypePassByValue, 1 << 22);
+ASSERT_DIFLAG_VALUE(FlagTypePassByReference, 1 << 23);
+ASSERT_DIFLAG_VALUE(FlagEnumClass, 1 << 24);
+ASSERT_DIFLAG_VALUE(FlagThunk, 1 << 25);
+ASSERT_DIFLAG_VALUE(FlagNonTrivial, 1 << 26);
+ASSERT_DIFLAG_VALUE(FlagBigEndian, 1 << 27);
+ASSERT_DIFLAG_VALUE(FlagLittleEndian, 1 << 28);
+ASSERT_DIFLAG_VALUE(FlagIndirectVirtualBase, (1 << 2) | (1 << 5));
+#undef ASSERT_DIFLAG_VALUE
+
+// There are two potential ways to convert `LLVMDIFlags` to `DIFlags`:
+// - Check and copy every individual bit/subvalue from input to output.
+// - Statically assert that both have the same layout, and cast.
+// As long as the static assertions succeed, a cast is easier and faster.
+// In the (hopefully) unlikely event that the assertions do fail someday, and
+// LLVM doesn't expose its own conversion function, we'll have to switch over
+// to copying each bit/subvalue.
+static DINode::DIFlags fromRust(LLVMDIFlags Flags) {
+  // Check that all set bits are covered by the static assertions above.
+  const unsigned UNKNOWN_BITS = (1 << 31) | (1 << 30) | (1 << 29) | (1 << 21);
+  if (Flags & UNKNOWN_BITS) {
+    report_fatal_error("bad LLVMDIFlags");
+  }
+
+  // As long as the static assertions are satisfied and no unknown bits are
+  // present, we can convert from `LLVMDIFlags` to `DIFlags` with a cast.
+  return static_cast<DINode::DIFlags>(Flags);
 }
 
 // These values **must** match debuginfo::DISPFlags! They also *happen*
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 6512176cc4a..a6db12f8932 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -417,7 +417,8 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         // Any descendants of `std` should be private. These crates are usually not marked
         // private in metadata, so we ignore that field.
         if extern_private.is_none()
-            && dep_root.map_or(false, |d| STDLIB_STABLE_CRATES.contains(&d.name))
+            && let Some(dep) = dep_root
+            && STDLIB_STABLE_CRATES.contains(&dep.name)
         {
             return true;
         }
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 5d78bed5cf8..926760b84aa 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -12,7 +12,7 @@ use rustc_hir::*;
 use rustc_hir_pretty as pprust_hir;
 use rustc_middle::hir::nested_filter;
 use rustc_span::def_id::StableCrateId;
-use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
+use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym, with_metavar_spans};
 
 use crate::hir::ModuleItems;
 use crate::middle::debugger_visualizer::DebuggerVisualizerFile;
@@ -1117,6 +1117,9 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh {
         // the fly in the resolver, storing only their accumulated hash in `ResolverGlobalCtxt`,
         // and combining it with other hashes here.
         resolutions.visibilities_for_hashing.hash_stable(&mut hcx, &mut stable_hasher);
+        with_metavar_spans(|mspans| {
+            mspans.freeze_and_get_read_spans().hash_stable(&mut hcx, &mut stable_hasher);
+        });
         stable_hasher.finish()
     });
 
diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs
index 1231ea88569..60e1ff1d049 100644
--- a/compiler/rustc_middle/src/mir/consts.rs
+++ b/compiler/rustc_middle/src/mir/consts.rs
@@ -467,9 +467,6 @@ impl<'tcx> Const<'tcx> {
                 let const_val = tcx.valtree_to_const_val((ty, valtree));
                 Self::Val(const_val, ty)
             }
-            ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => {
-                Self::Unevaluated(UnevaluatedConst { def, args, promoted: None }, ty)
-            }
             _ => Self::Ty(ty, c),
         }
     }
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index cd6b2d65bf1..65f51ae9d39 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -71,11 +71,7 @@ impl ConditionId {
 
 /// Enum that can hold a constant zero value, the ID of an physical coverage
 /// counter, or the ID of a coverage-counter expression.
-///
-/// This was originally only used for expression operands (and named `Operand`),
-/// but the zero/counter/expression distinction is also useful for representing
-/// the value of code/gap mappings, and the true/false arms of branch mappings.
-#[derive(Copy, Clone, PartialEq, Eq)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
 #[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
 pub enum CovTerm {
     Zero,
@@ -171,7 +167,7 @@ impl Op {
     }
 }
 
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq, Eq)]
 #[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
 pub struct Expression {
     pub lhs: CovTerm,
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index d6f8fed755f..1b07846e0cf 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -222,7 +222,7 @@ impl AllocError {
 }
 
 /// The information that makes up a memory access: offset and size.
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, PartialEq)]
 pub struct AllocRange {
     pub start: Size,
     pub size: Size,
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
index 3a83b184d83..78196b05361 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
@@ -97,7 +97,7 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
         debug_assert!(prov.len() <= 1);
         if let Some(entry) = prov.first() {
             // If it overlaps with this byte, it is on this byte.
-            debug_assert!(self.bytes.as_ref().map_or(true, |b| b.get(&offset).is_none()));
+            debug_assert!(self.bytes.as_ref().is_none_or(|b| !b.contains_key(&offset)));
             Some(entry.1)
         } else {
             // Look up per-byte provenance.
@@ -301,7 +301,7 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
                 // For really small copies, make sure we don't start before `src` does.
                 let entry_start = cmp::max(entry.0, src.start);
                 for offset in entry_start..src.end() {
-                    if bytes.last().map_or(true, |bytes_entry| bytes_entry.0 < offset) {
+                    if bytes.last().is_none_or(|bytes_entry| bytes_entry.0 < offset) {
                         // The last entry, if it exists, has a lower offset than us.
                         bytes.push((offset, entry.1));
                     } else {
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 24d2478f770..ea35323ccc7 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -1068,6 +1068,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                 pretty_print_const(b, fmt, false)?;
                 write!(fmt, "]")
             }
+            Len(ref a) => write!(fmt, "Len({a:?})"),
             Cast(ref kind, ref place, ref ty) => {
                 with_no_trimmed_paths!(write!(fmt, "{place:?} as {ty} ({kind:?})"))
             }
diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs
index 470a247d794..609d5647d04 100644
--- a/compiler/rustc_middle/src/mir/statement.rs
+++ b/compiler/rustc_middle/src/mir/statement.rs
@@ -424,6 +424,7 @@ impl<'tcx> Rvalue<'tcx> {
             | Rvalue::Ref(_, _, _)
             | Rvalue::ThreadLocalRef(_)
             | Rvalue::RawPtr(_, _)
+            | Rvalue::Len(_)
             | Rvalue::Cast(
                 CastKind::IntToInt
                 | CastKind::FloatToInt
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index bbbaffc5a35..0c17a2e0fe5 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -1351,6 +1351,16 @@ pub enum Rvalue<'tcx> {
     /// model.
     RawPtr(Mutability, Place<'tcx>),
 
+    /// Yields the length of the place, as a `usize`.
+    ///
+    /// If the type of the place is an array, this is the array length. For slices (`[T]`, not
+    /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is
+    /// ill-formed for places of other types.
+    ///
+    /// This cannot be a `UnOp(PtrMetadata, _)` because that expects a value, and we only
+    /// have a place, and `UnOp(PtrMetadata, RawPtr(place))` is not a thing.
+    Len(Place<'tcx>),
+
     /// Performs essentially all of the casts that can be performed via `as`.
     ///
     /// This allows for casts from/to a variety of types.
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index cbb26b83c79..db77017310a 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -210,6 +210,7 @@ impl<'tcx> Rvalue<'tcx> {
                 let place_ty = place.ty(local_decls, tcx).ty;
                 Ty::new_ptr(tcx, place_ty, mutability)
             }
+            Rvalue::Len(..) => tcx.types.usize,
             Rvalue::Cast(.., ty) => ty,
             Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) => {
                 let lhs_ty = lhs.ty(local_decls, tcx);
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 12a024a219e..058acbd4024 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -695,6 +695,14 @@ macro_rules! make_mir_visitor {
                         self.visit_place(path, ctx, location);
                     }
 
+                    Rvalue::Len(path) => {
+                        self.visit_place(
+                            path,
+                            PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
+                            location
+                        );
+                    }
+
                     Rvalue::Cast(_cast_kind, operand, ty) => {
                         self.visit_operand(operand, location);
                         self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
diff --git a/compiler/rustc_middle/src/query/arena_cached.rs b/compiler/rustc_middle/src/query/arena_cached.rs
new file mode 100644
index 00000000000..ec6e466ff68
--- /dev/null
+++ b/compiler/rustc_middle/src/query/arena_cached.rs
@@ -0,0 +1,47 @@
+/// Helper trait that allows `arena_cache` queries to return `Option<&T>`
+/// instead of `&Option<T>`, and avoid allocating `None` in the arena.
+///
+/// An arena-cached query must be declared to return a type that implements
+/// this trait, i.e. either `&'tcx T` or `Option<&'tcx T>`. This trait then
+/// determines the types returned by the provider and stored in the arena,
+/// and provides a function to bridge between the three types.
+pub trait ArenaCached<'tcx>: Sized {
+    /// Type that is returned by the query provider.
+    type Provided;
+    /// Type that is stored in the arena.
+    type Allocated: 'tcx;
+
+    /// Takes a provided value, and allocates it in the arena (if appropriate)
+    /// with the help of the given `arena_alloc` closure.
+    fn alloc_in_arena(
+        arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated,
+        value: Self::Provided,
+    ) -> Self;
+}
+
+impl<'tcx, T> ArenaCached<'tcx> for &'tcx T {
+    type Provided = T;
+    type Allocated = T;
+
+    fn alloc_in_arena(
+        arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated,
+        value: Self::Provided,
+    ) -> Self {
+        // Just allocate in the arena normally.
+        arena_alloc(value)
+    }
+}
+
+impl<'tcx, T> ArenaCached<'tcx> for Option<&'tcx T> {
+    type Provided = Option<T>;
+    /// The provide value is `Option<T>`, but we only store `T` in the arena.
+    type Allocated = T;
+
+    fn alloc_in_arena(
+        arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated,
+        value: Self::Provided,
+    ) -> Self {
+        // Don't store None in the arena, and wrap the allocated reference in Some.
+        value.map(arena_alloc)
+    }
+}
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index bfbcb0532c1..05ded71dbeb 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -7,7 +7,6 @@
 #![allow(unused_parens)]
 
 use std::mem;
-use std::ops::Deref;
 use std::path::PathBuf;
 use std::sync::Arc;
 
@@ -85,6 +84,7 @@ use crate::ty::{
 };
 use crate::{dep_graph, mir, thir};
 
+mod arena_cached;
 pub mod erase;
 mod keys;
 pub use keys::{AsLocalKey, Key, LocalCrate};
@@ -586,7 +586,7 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    query mir_coroutine_witnesses(key: DefId) -> &'tcx Option<mir::CoroutineLayout<'tcx>> {
+    query mir_coroutine_witnesses(key: DefId) -> Option<&'tcx mir::CoroutineLayout<'tcx>> {
         arena_cache
         desc { |tcx| "coroutine witness types for `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
@@ -1164,8 +1164,7 @@ rustc_queries! {
     }
 
     /// Check whether the function has any recursion that could cause the inliner to trigger
-    /// a cycle. Returns the call stack causing the cycle. The call stack does not contain the
-    /// current function, just all intermediate functions.
+    /// a cycle.
     query mir_callgraph_reachable(key: (ty::Instance<'tcx>, LocalDefId)) -> bool {
         fatal_cycle
         desc { |tcx|
@@ -2416,7 +2415,7 @@ rustc_queries! {
     /// because the `ty::Ty`-based wfcheck is always run.
     query diagnostic_hir_wf_check(
         key: (ty::Predicate<'tcx>, WellFormedLoc)
-    ) -> &'tcx Option<ObligationCause<'tcx>> {
+    ) -> Option<&'tcx ObligationCause<'tcx>> {
         arena_cache
         eval_always
         no_hash
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index 2cb6f6d8c6e..1c157f33a81 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -289,10 +289,10 @@ macro_rules! define_callbacks {
 
                 /// This type alias specifies the type returned from query providers and the type
                 /// used for decoding. For regular queries this is the declared returned type `V`,
-                /// but `arena_cache` will use `<V as Deref>::Target` instead.
+                /// but `arena_cache` will use `<V as ArenaCached>::Provided` instead.
                 pub type ProvidedValue<'tcx> = query_if_arena!(
                     [$($modifiers)*]
-                    (<$V as Deref>::Target)
+                    (<$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Provided)
                     ($V)
                 );
 
@@ -307,10 +307,18 @@ macro_rules! define_callbacks {
                 ) -> Erase<Value<'tcx>> {
                     erase(query_if_arena!([$($modifiers)*]
                         {
-                            if mem::needs_drop::<ProvidedValue<'tcx>>() {
-                                &*_tcx.query_system.arenas.$name.alloc(value)
+                            use $crate::query::arena_cached::ArenaCached;
+
+                            if mem::needs_drop::<<$V as ArenaCached<'tcx>>::Allocated>() {
+                                <$V as ArenaCached>::alloc_in_arena(
+                                    |v| _tcx.query_system.arenas.$name.alloc(v),
+                                    value,
+                                )
                             } else {
-                                &*_tcx.arena.dropless.alloc(value)
+                                <$V as ArenaCached>::alloc_in_arena(
+                                    |v| _tcx.arena.dropless.alloc(v),
+                                    value,
+                                )
                             }
                         }
                         (value)
@@ -354,7 +362,7 @@ macro_rules! define_callbacks {
 
         pub struct QueryArenas<'tcx> {
             $($(#[$attr])* pub $name: query_if_arena!([$($modifiers)*]
-                (TypedArena<<$V as Deref>::Target>)
+                (TypedArena<<$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Allocated>)
                 ()
             ),)*
         }
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index db2bb8a7248..55d78e083e0 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -345,9 +345,6 @@ pub enum ObligationCauseCode<'tcx> {
     /// `main` has wrong type
     MainFunctionType,
 
-    /// `start` has wrong type
-    StartFunctionType,
-
     /// language function has wrong type
     LangFunctionType(Symbol),
 
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index 33d39b137b6..c4d5367e2f0 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -433,7 +433,7 @@ pub fn analyze_coroutine_closure_captures<'a, 'tcx: 'a, T>(
                 // A parent matches a child if they share the same prefix of projections.
                 // The child may have more, if it is capturing sub-fields out of
                 // something that is captured by-move in the parent closure.
-                while child_captures.peek().map_or(false, |(_, child_capture)| {
+                while child_captures.peek().is_some_and(|(_, child_capture)| {
                     child_prefix_matches_parent_projections(parent_capture, child_capture)
                 }) {
                     let (child_field_idx, child_capture) = child_captures.next().unwrap();
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 7035e641f39..2d76f6ec7d6 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -52,7 +52,9 @@ use rustc_type_ir::TyKind::*;
 use rustc_type_ir::fold::TypeFoldable;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
 pub use rustc_type_ir::lift::Lift;
-use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo, search_graph};
+use rustc_type_ir::{
+    CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo, elaborate, search_graph,
+};
 use tracing::{debug, instrument};
 
 use crate::arena::Arena;
@@ -2558,7 +2560,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name`
     /// returns true if the `trait_def_id` defines an associated item of name `assoc_name`.
     pub fn trait_may_define_assoc_item(self, trait_def_id: DefId, assoc_name: Ident) -> bool {
-        self.supertrait_def_ids(trait_def_id).any(|trait_did| {
+        elaborate::supertrait_def_ids(self, trait_def_id).any(|trait_did| {
             self.associated_items(trait_did)
                 .filter_by_name_unhygienic(assoc_name.name)
                 .any(|item| self.hygienic_eq(assoc_name, item.ident(self), trait_did))
@@ -2579,14 +2581,6 @@ impl<'tcx> TyCtxt<'tcx> {
         })
     }
 
-    /// Computes the def-ids of the transitive supertraits of `trait_def_id`. This (intentionally)
-    /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used
-    /// to identify which traits may define a given associated type to help avoid cycle errors,
-    /// and to make size estimates for vtable layout computation.
-    pub fn supertrait_def_ids(self, trait_def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx {
-        rustc_type_ir::elaborate::supertrait_def_ids(self, trait_def_id)
-    }
-
     /// Given a closure signature, returns an equivalent fn signature. Detuples
     /// and so forth -- so e.g., if we have a sig with `Fn<(u32, i32)>` then
     /// you would get a `fn(u32, i32)`.
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 77745599afb..e4187d2760c 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -336,7 +336,7 @@ pub fn suggest_constraining_type_params<'a>(
             .collect();
 
         constraints
-            .retain(|(_, def_id, _)| def_id.map_or(true, |def| !bound_trait_defs.contains(&def)));
+            .retain(|(_, def_id, _)| def_id.is_none_or(|def| !bound_trait_defs.contains(&def)));
 
         if constraints.is_empty() {
             continue;
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index e4ded2c30f5..b7a648aae3f 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -328,7 +328,7 @@ impl<'tcx> InstanceKind<'tcx> {
             // We include enums without destructors to allow, say, optimizing
             // drops of `Option::None` before LTO. We also respect the intent of
             // `#[inline]` on `Drop::drop` implementations.
-            return ty.ty_adt_def().map_or(true, |adt_def| {
+            return ty.ty_adt_def().is_none_or(|adt_def| {
                 match *self {
                     ty::InstanceKind::DropGlue(..) => adt_def.destructor(tcx).map(|dtor| dtor.did),
                     ty::InstanceKind::AsyncDropGlueCtorShim(..) => {
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index d2875fb3794..ca70ae794c5 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -79,8 +79,7 @@ pub use self::predicate::{
     PolyExistentialPredicate, PolyExistentialProjection, PolyExistentialTraitRef,
     PolyProjectionPredicate, PolyRegionOutlivesPredicate, PolySubtypePredicate, PolyTraitPredicate,
     PolyTraitRef, PolyTypeOutlivesPredicate, Predicate, PredicateKind, ProjectionPredicate,
-    RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, TraitPredicate, TraitRef,
-    TypeOutlivesPredicate,
+    RegionOutlivesPredicate, SubtypePredicate, TraitPredicate, TraitRef, TypeOutlivesPredicate,
 };
 pub use self::region::{
     BoundRegion, BoundRegionKind, EarlyParamRegion, LateParamRegion, LateParamRegionKind, Region,
diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs
index 32d6455e825..584cac22ae8 100644
--- a/compiler/rustc_middle/src/ty/predicate.rs
+++ b/compiler/rustc_middle/src/ty/predicate.rs
@@ -476,16 +476,6 @@ impl<'tcx> Clause<'tcx> {
     }
 }
 
-pub trait ToPolyTraitRef<'tcx> {
-    fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>;
-}
-
-impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> {
-    fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> {
-        self.map_bound_ref(|trait_pred| trait_pred.trait_ref)
-    }
-}
-
 impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PredicateKind<'tcx>> for Predicate<'tcx> {
     fn upcast_from(from: PredicateKind<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
         ty::Binder::dummy(from).upcast(tcx)
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index bf37ae05c82..a9a47c87a38 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1894,11 +1894,11 @@ impl<'tcx> Ty<'tcx> {
 
             ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => false,
 
-            ty::Tuple(tys) => tys.last().map_or(true, |ty| ty.is_trivially_sized(tcx)),
+            ty::Tuple(tys) => tys.last().is_none_or(|ty| ty.is_trivially_sized(tcx)),
 
             ty::Adt(def, args) => def
                 .sized_constraint(tcx)
-                .map_or(true, |ty| ty.instantiate(tcx, args).is_trivially_sized(tcx)),
+                .is_none_or(|ty| ty.instantiate(tcx, args).is_trivially_sized(tcx)),
 
             ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) | ty::Bound(..) => false,
 
diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs
index 09a05104e49..23e2e8ad3d3 100644
--- a/compiler/rustc_middle/src/ty/vtable.rs
+++ b/compiler/rustc_middle/src/ty/vtable.rs
@@ -2,6 +2,7 @@ use std::fmt;
 
 use rustc_ast::Mutability;
 use rustc_macros::HashStable;
+use rustc_type_ir::elaborate;
 
 use crate::mir::interpret::{AllocId, Allocation, CTFE_ALLOC_SALT, Pointer, Scalar, alloc_range};
 use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt};
@@ -64,7 +65,7 @@ pub(crate) fn vtable_min_entries<'tcx>(
     };
 
     // This includes self in supertraits.
-    for def_id in tcx.supertrait_def_ids(trait_ref.def_id()) {
+    for def_id in elaborate::supertrait_def_ids(tcx, trait_ref.def_id()) {
         count += tcx.own_existential_vtable_entries(def_id).len();
     }
 
diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs
index 390909bb0ab..9120a248d95 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -360,7 +360,7 @@ fn find_item_ty_spans(
             if let Res::Def(kind, def_id) = path.res
                 && matches!(kind, DefKind::Enum | DefKind::Struct | DefKind::Union)
             {
-                let check_params = def_id.as_local().map_or(true, |def_id| {
+                let check_params = def_id.as_local().is_none_or(|def_id| {
                     if def_id == needle {
                         spans.push(ty.span);
                     }
diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index 5203c33c968..ffdb721fb18 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -118,12 +118,6 @@ mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
     .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
     .label = use of extern static
 
-mir_build_force_inline =
-    `{$callee}` is incompatible with `#[rustc_force_inline]`
-    .attr = annotation here
-    .callee = `{$callee}` defined here
-    .note = incompatible due to: {$reason}
-
 mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
 
 mir_build_initializing_type_with_requires_unsafe =
@@ -330,12 +324,6 @@ mir_build_type_not_structural_more_info = see https://doc.rust-lang.org/stable/s
 mir_build_type_not_structural_tip =
     the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
-mir_build_unconditional_recursion = function cannot return without recursing
-    .label = cannot return without recursing
-    .help = a `loop` may express intention better if this is on purpose
-
-mir_build_unconditional_recursion_call_site_label = recursive call site
-
 mir_build_union_field_requires_unsafe =
     access to union field is unsafe and requires unsafe block
     .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs
index 3dd5de02230..59f440432eb 100644
--- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs
@@ -246,6 +246,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
                 let offset = self.parse_operand(args[1])?;
                 Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset))))
             },
+            @call(mir_len, args) => Ok(Rvalue::Len(self.parse_place(args[0])?)),
             @call(mir_ptr_metadata, args) => Ok(Rvalue::UnaryOp(UnOp::PtrMetadata, self.parse_operand(args[0])?)),
             @call(mir_copy_for_deref, args) => Ok(Rvalue::CopyForDeref(self.parse_place(args[0])?)),
             ExprKind::Borrow { borrow_kind, arg } => Ok(
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 89c7bb357ef..b1851e79d5c 100644
--- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs
@@ -11,7 +11,7 @@ use rustc_middle::mir::*;
 use rustc_middle::thir::*;
 use rustc_middle::ty::{self, AdtDef, CanonicalUserTypeAnnotation, Ty, Variance};
 use rustc_middle::{bug, span_bug};
-use rustc_span::{DesugaringKind, Span};
+use rustc_span::Span;
 use tracing::{debug, instrument, trace};
 
 use crate::builder::ForGuard::{OutsideGuard, RefWithinGuard};
@@ -630,98 +630,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         block.and(base_place.index(idx))
     }
 
-    /// Given a place that's either an array or a slice, returns an operand
-    /// with the length of the array/slice.
-    ///
-    /// For arrays it'll be `Operand::Constant` with the actual length;
-    /// For slices it'll be `Operand::Move` of a local using `PtrMetadata`.
-    pub(in crate::builder) fn len_of_slice_or_array(
-        &mut self,
-        block: BasicBlock,
-        place: Place<'tcx>,
-        span: Span,
-        source_info: SourceInfo,
-    ) -> Operand<'tcx> {
-        let place_ty = place.ty(&self.local_decls, self.tcx).ty;
-        let usize_ty = self.tcx.types.usize;
-
-        match place_ty.kind() {
-            ty::Array(_elem_ty, len_const) => {
-                let ty_const = if let Some((_, len_ty)) = len_const.try_to_valtree()
-                    && len_ty != self.tcx.types.usize
-                {
-                    // Bad const generics can give us a constant from the type that's
-                    // not actually a `usize`, so in that case give an error instead.
-                    // FIXME: It'd be nice if the type checker made sure this wasn't
-                    // possible, instead.
-                    let err = self.tcx.dcx().span_delayed_bug(
-                        span,
-                        format!(
-                            "Array length should have already been a type error, as it's {len_ty:?}"
-                        ),
-                    );
-                    ty::Const::new_error(self.tcx, err)
-                } else {
-                    // We know how long an array is, so just use that as a constant
-                    // directly -- no locals needed. We do need one statement so
-                    // that borrow- and initialization-checking consider it used,
-                    // though. FIXME: Do we really *need* to count this as a use?
-                    // Could partial array tracking work off something else instead?
-                    self.cfg.push_fake_read(block, source_info, FakeReadCause::ForIndex, place);
-                    *len_const
-                };
-
-                let const_ = Const::from_ty_const(ty_const, usize_ty, self.tcx);
-                Operand::Constant(Box::new(ConstOperand { span, user_ty: None, const_ }))
-            }
-            ty::Slice(_elem_ty) => {
-                let ptr_or_ref = if let [PlaceElem::Deref] = place.projection[..]
-                    && let local_ty = self.local_decls[place.local].ty
-                    && local_ty.is_trivially_pure_clone_copy()
-                {
-                    // It's extremely common that we have something that can be
-                    // directly passed to `PtrMetadata`, so avoid an unnecessary
-                    // temporary and statement in those cases. Note that we can
-                    // only do that for `Copy` types -- not `&mut [_]` -- because
-                    // the MIR we're building here needs to pass NLL later.
-                    Operand::Copy(Place::from(place.local))
-                } else {
-                    let len_span = self.tcx.with_stable_hashing_context(|hcx| {
-                        let span = source_info.span;
-                        span.mark_with_reason(
-                            None,
-                            DesugaringKind::IndexBoundsCheckReborrow,
-                            span.edition(),
-                            hcx,
-                        )
-                    });
-                    let ptr_ty = Ty::new_imm_ptr(self.tcx, place_ty);
-                    let slice_ptr = self.temp(ptr_ty, span);
-                    self.cfg.push_assign(
-                        block,
-                        SourceInfo { span: len_span, ..source_info },
-                        slice_ptr,
-                        Rvalue::RawPtr(Mutability::Not, place),
-                    );
-                    Operand::Move(slice_ptr)
-                };
-
-                let len = self.temp(usize_ty, span);
-                self.cfg.push_assign(
-                    block,
-                    source_info,
-                    len,
-                    Rvalue::UnaryOp(UnOp::PtrMetadata, ptr_or_ref),
-                );
-
-                Operand::Move(len)
-            }
-            _ => {
-                span_bug!(span, "len called on place of type {place_ty:?}")
-            }
-        }
-    }
-
     fn bounds_check(
         &mut self,
         block: BasicBlock,
@@ -730,25 +638,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         expr_span: Span,
         source_info: SourceInfo,
     ) -> BasicBlock {
-        let slice = slice.to_place(self);
+        let usize_ty = self.tcx.types.usize;
+        let bool_ty = self.tcx.types.bool;
+        // bounds check:
+        let len = self.temp(usize_ty, expr_span);
+        let lt = self.temp(bool_ty, expr_span);
 
         // len = len(slice)
-        let len = self.len_of_slice_or_array(block, slice, expr_span, source_info);
-
+        self.cfg.push_assign(block, source_info, len, Rvalue::Len(slice.to_place(self)));
         // lt = idx < len
-        let bool_ty = self.tcx.types.bool;
-        let lt = self.temp(bool_ty, expr_span);
         self.cfg.push_assign(
             block,
             source_info,
             lt,
             Rvalue::BinaryOp(
                 BinOp::Lt,
-                Box::new((Operand::Copy(Place::from(index)), len.to_copy())),
+                Box::new((Operand::Copy(Place::from(index)), Operand::Copy(len))),
             ),
         );
-        let msg = BoundsCheck { len, index: Operand::Copy(Place::from(index)) };
-
+        let msg = BoundsCheck { len: Operand::Move(len), index: Operand::Copy(Place::from(index)) };
         // assert!(lt, "...")
         self.assert(block, Operand::Move(lt), true, msg, expr_span)
     }
diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs
index b944d13fb0d..b21ec8f3083 100644
--- a/compiler/rustc_mir_build/src/builder/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs
@@ -1986,6 +1986,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             return;
         }
 
+        let false_edge_start_block = candidate.subcandidates[0].false_edge_start_block;
         candidate.subcandidates.retain_mut(|candidate| {
             if candidate.extra_data.is_never {
                 candidate.visit_leaves(|subcandidate| {
@@ -2000,8 +2001,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
         });
         if candidate.subcandidates.is_empty() {
-            // If `candidate` has become a leaf candidate, ensure it has a `pre_binding_block`.
-            candidate.pre_binding_block = Some(self.cfg.start_new_block());
+            // If `candidate` has become a leaf candidate, ensure it has a `pre_binding_block` and `otherwise_block`.
+            let next_block = self.cfg.start_new_block();
+            candidate.pre_binding_block = Some(next_block);
+            candidate.otherwise_block = Some(next_block);
+            // In addition, if `candidate` doesn't have `false_edge_start_block`, it should be assigned here.
+            if candidate.false_edge_start_block.is_none() {
+                candidate.false_edge_start_block = false_edge_start_block;
+            }
         }
     }
 
diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs
index 0d36b7bb3ee..8cca84d7fcc 100644
--- a/compiler/rustc_mir_build/src/builder/matches/test.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/test.rs
@@ -243,8 +243,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
 
             TestKind::Len { len, op } => {
+                let usize_ty = self.tcx.types.usize;
+                let actual = self.temp(usize_ty, test.span);
+
                 // actual = len(place)
-                let actual = self.len_of_slice_or_array(block, place, test.span, source_info);
+                self.cfg.push_assign(block, source_info, actual, Rvalue::Len(place));
 
                 // expected = <N>
                 let expected = self.push_usize(block, source_info, len);
@@ -259,7 +262,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     fail_block,
                     source_info,
                     op,
-                    actual,
+                    Operand::Move(actual),
                     Operand::Move(expected),
                 );
             }
diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs
index 8b01ec0d06a..9fa431f7d5f 100644
--- a/compiler/rustc_mir_build/src/builder/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/mod.rs
@@ -26,10 +26,8 @@ use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt, TypingMode
 use rustc_middle::{bug, span_bug};
 use rustc_span::{Span, Symbol, sym};
 
-use super::lints;
 use crate::builder::expr::as_place::PlaceBuilder;
 use crate::builder::scope::DropKind;
-use crate::check_inline;
 
 pub(crate) fn closure_saved_names_of_captured_variables<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -48,7 +46,7 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>(
 }
 
 /// Construct the MIR for a given `DefId`.
-pub(crate) fn mir_build<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx> {
+pub(crate) fn build_mir<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx> {
     let tcx = tcx.tcx;
     tcx.ensure_with_value().thir_abstract_const(def);
     if let Err(e) = tcx.check_match(def) {
@@ -80,9 +78,6 @@ pub(crate) fn mir_build<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx
         }
     };
 
-    lints::check(tcx, &body);
-    check_inline::check_force_inline(tcx, &body);
-
     // The borrow checker will replace all the regions here with its own
     // inference variables. There's no point having non-erased regions here.
     // The exception is `body.user_type_annotations`, which is used unmodified
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 5eed9ef798d..995bc311b7c 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -266,7 +266,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for LayoutConstrainedPlaceVisitor<'a, 'tcx> {
             // place, i.e. the expression is a place expression and not a dereference
             // (since dereferencing something leads us to a different place).
             ExprKind::Deref { .. } => {}
-            ref kind if ExprCategory::of(kind).map_or(true, |cat| cat == ExprCategory::Place) => {
+            ref kind if ExprCategory::of(kind).is_none_or(|cat| cat == ExprCategory::Place) => {
                 visit::walk_expr(self, expr);
             }
 
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 90c31a2caa3..83aec9ccdef 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -12,16 +12,6 @@ use rustc_span::{Span, Symbol};
 use crate::fluent_generated as fluent;
 
 #[derive(LintDiagnostic)]
-#[diag(mir_build_unconditional_recursion)]
-#[help]
-pub(crate) struct UnconditionalRecursion {
-    #[label]
-    pub(crate) span: Span,
-    #[label(mir_build_unconditional_recursion_call_site_label)]
-    pub(crate) call_sites: Vec<Span>,
-}
-
-#[derive(LintDiagnostic)]
 #[diag(mir_build_call_to_deprecated_safe_fn_requires_unsafe)]
 pub(crate) struct CallToDeprecatedSafeFnRequiresUnsafe {
     #[label]
@@ -1107,15 +1097,3 @@ impl<'a> Subdiagnostic for Rust2024IncompatiblePatSugg<'a> {
         );
     }
 }
-
-#[derive(Diagnostic)]
-#[diag(mir_build_force_inline)]
-#[note]
-pub(crate) struct InvalidForceInline {
-    #[primary_span]
-    pub attr_span: Span,
-    #[label(mir_build_callee)]
-    pub callee_span: Span,
-    pub callee: String,
-    pub reason: &'static str,
-}
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index 76a35355de7..8e786733ee0 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -15,11 +15,9 @@
 // "Go to file" feature to silently ignore all files in the module, probably
 // because it assumes that "build" is a build-output directory. See #134365.
 mod builder;
-pub mod check_inline;
 mod check_tail_calls;
 mod check_unsafety;
 mod errors;
-pub mod lints;
 mod thir;
 
 use rustc_middle::util::Providers;
@@ -29,7 +27,7 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 pub fn provide(providers: &mut Providers) {
     providers.check_match = thir::pattern::check_match;
     providers.lit_to_const = thir::constant::lit_to_const;
-    providers.hooks.build_mir = builder::mir_build;
+    providers.hooks.build_mir = builder::build_mir;
     providers.closure_saved_names_of_captured_variables =
         builder::closure_saved_names_of_captured_variables;
     providers.check_unsafety = check_unsafety::check_unsafety;
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 a13b00e1921..b5b7b54a1cc 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -1086,14 +1086,13 @@ fn find_fallback_pattern_typo<'tcx>(
                 let vis = cx.tcx.visibility(item.owner_id);
                 if vis.is_accessible_from(parent, cx.tcx) {
                     accessible.push(item_name);
-                    let path = if item_name == name {
-                        // We know that the const wasn't in scope because it has the exact
-                        // same name, so we suggest the full path.
-                        with_no_trimmed_paths!(cx.tcx.def_path_str(item.owner_id))
-                    } else {
-                        // The const is likely just typoed, and nothing else.
-                        cx.tcx.def_path_str(item.owner_id)
-                    };
+                    // FIXME: the line below from PR #135310 is a workaround for the ICE in issue
+                    // #135289, where a macro in a dependency can create unreachable patterns in the
+                    // current crate. Path trimming expects diagnostics for a typoed const, but no
+                    // diagnostics are emitted and we ICE. See
+                    // `tests/ui/resolve/const-with-typo-in-pattern-binding-ice-135289.rs` for a
+                    // test that reproduces the ICE if we don't use `with_no_trimmed_paths!`.
+                    let path = with_no_trimmed_paths!(cx.tcx.def_path_str(item.owner_id));
                     accessible_path.push(path);
                 } else if name == item_name {
                     // The const exists somewhere in this crate, but it can't be imported
diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index e457b514936..9ccabb46c63 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -608,7 +608,7 @@ where
         let before = diffs_before.as_mut().map(next_in_dataflow_order);
 
         assert!(diffs_after.is_empty());
-        assert!(diffs_before.as_ref().map_or(true, ExactSizeIterator::is_empty));
+        assert!(diffs_before.as_ref().is_none_or(ExactSizeIterator::is_empty));
 
         let terminator = self.cursor.body()[block].terminator();
         let mut terminator_str = String::new();
diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
index f2ef5018c49..df4b1a53417 100644
--- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
@@ -91,6 +91,7 @@ where
             | Rvalue::Use(..)
             | Rvalue::ThreadLocalRef(..)
             | Rvalue::Repeat(..)
+            | Rvalue::Len(..)
             | Rvalue::BinaryOp(..)
             | Rvalue::NullaryOp(..)
             | Rvalue::UnaryOp(..)
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index 80875f32e4f..d1b3a389e9e 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -413,6 +413,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
             Rvalue::Ref(..)
             | Rvalue::RawPtr(..)
             | Rvalue::Discriminant(..)
+            | Rvalue::Len(..)
             | Rvalue::NullaryOp(
                 NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..) | NullOp::UbChecks,
                 _,
diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl
index b0c023cca82..5628f4c9381 100644
--- a/compiler/rustc_mir_transform/messages.ftl
+++ b/compiler/rustc_mir_transform/messages.ftl
@@ -27,6 +27,12 @@ mir_transform_force_inline =
     .callee = `{$callee}` defined here
     .note = could not be inlined due to: {$reason}
 
+mir_transform_force_inline_attr =
+    `{$callee}` is incompatible with `#[rustc_force_inline]`
+    .attr = annotation here
+    .callee = `{$callee}` defined here
+    .note = incompatible due to: {$reason}
+
 mir_transform_force_inline_justification =
     `{$callee}` is required to be inlined to: {$sym}
 
@@ -66,6 +72,12 @@ mir_transform_unaligned_packed_ref = reference to packed field is unaligned
     .note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
     .help = copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
+mir_transform_unconditional_recursion = function cannot return without recursing
+    .label = cannot return without recursing
+    .help = a `loop` may express intention better if this is on purpose
+
+mir_transform_unconditional_recursion_call_site_label = recursive call site
+
 mir_transform_undefined_transmute = pointers cannot be transmuted to integers during const eval
     .note = at compile-time, pointers do not have an integer value
     .note2 = avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_transform/src/check_call_recursion.rs
index 5cf33868ade..51fd3c6512e 100644
--- a/compiler/rustc_mir_build/src/lints.rs
+++ b/compiler/rustc_mir_transform/src/check_call_recursion.rs
@@ -10,25 +10,54 @@ use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
 use rustc_span::Span;
 
 use crate::errors::UnconditionalRecursion;
+use crate::pass_manager::MirLint;
 
-pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
-    check_call_recursion(tcx, body);
+pub(super) struct CheckCallRecursion;
+
+impl<'tcx> MirLint<'tcx> for CheckCallRecursion {
+    fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
+        let def_id = body.source.def_id().expect_local();
+
+        if let DefKind::Fn | DefKind::AssocFn = tcx.def_kind(def_id) {
+            // If this is trait/impl method, extract the trait's args.
+            let trait_args = match tcx.trait_of_item(def_id.to_def_id()) {
+                Some(trait_def_id) => {
+                    let trait_args_count = tcx.generics_of(trait_def_id).count();
+                    &GenericArgs::identity_for_item(tcx, def_id)[..trait_args_count]
+                }
+                _ => &[],
+            };
+
+            check_recursion(tcx, body, CallRecursion { trait_args })
+        }
+    }
 }
 
-fn check_call_recursion<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
-    let def_id = body.source.def_id().expect_local();
+/// Requires drop elaboration to have been performed.
+pub(super) struct CheckDropRecursion;
 
-    if let DefKind::Fn | DefKind::AssocFn = tcx.def_kind(def_id) {
-        // If this is trait/impl method, extract the trait's args.
-        let trait_args = match tcx.trait_of_item(def_id.to_def_id()) {
-            Some(trait_def_id) => {
-                let trait_args_count = tcx.generics_of(trait_def_id).count();
-                &GenericArgs::identity_for_item(tcx, def_id)[..trait_args_count]
-            }
-            _ => &[],
-        };
+impl<'tcx> MirLint<'tcx> for CheckDropRecursion {
+    fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
+        let def_id = body.source.def_id().expect_local();
 
-        check_recursion(tcx, body, CallRecursion { trait_args })
+        // First check if `body` is an `fn drop()` of `Drop`
+        if let DefKind::AssocFn = tcx.def_kind(def_id)
+        && let Some(trait_ref) =
+            tcx.impl_of_method(def_id.to_def_id()).and_then(|def_id| tcx.impl_trait_ref(def_id))
+        && let Some(drop_trait) = tcx.lang_items().drop_trait()
+        && drop_trait == trait_ref.instantiate_identity().def_id
+        // avoid erroneous `Drop` impls from causing ICEs below
+        && let sig = tcx.fn_sig(def_id).instantiate_identity()
+        && sig.inputs().skip_binder().len() == 1
+        {
+            // It was. Now figure out for what type `Drop` is implemented and then
+            // check for recursion.
+            if let ty::Ref(_, dropped_ty, _) =
+                tcx.liberate_late_bound_regions(def_id.to_def_id(), sig.input(0)).kind()
+            {
+                check_recursion(tcx, body, RecursiveDrop { drop_for: *dropped_ty });
+            }
+        }
     }
 }
 
@@ -61,30 +90,6 @@ fn check_recursion<'tcx>(
     }
 }
 
-/// Requires drop elaboration to have been performed first.
-pub fn check_drop_recursion<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
-    let def_id = body.source.def_id().expect_local();
-
-    // First check if `body` is an `fn drop()` of `Drop`
-    if let DefKind::AssocFn = tcx.def_kind(def_id)
-        && let Some(trait_ref) =
-            tcx.impl_of_method(def_id.to_def_id()).and_then(|def_id| tcx.impl_trait_ref(def_id))
-        && let Some(drop_trait) = tcx.lang_items().drop_trait()
-        && drop_trait == trait_ref.instantiate_identity().def_id
-        // avoid erroneous `Drop` impls from causing ICEs below
-        && let sig = tcx.fn_sig(def_id).instantiate_identity()
-        && sig.inputs().skip_binder().len() == 1
-    {
-        // It was. Now figure out for what type `Drop` is implemented and then
-        // check for recursion.
-        if let ty::Ref(_, dropped_ty, _) =
-            tcx.liberate_late_bound_regions(def_id.to_def_id(), sig.input(0)).kind()
-        {
-            check_recursion(tcx, body, RecursiveDrop { drop_for: *dropped_ty });
-        }
-    }
-}
-
 trait TerminatorClassifier<'tcx> {
     fn is_recursive_terminator(
         &self,
diff --git a/compiler/rustc_mir_build/src/check_inline.rs b/compiler/rustc_mir_transform/src/check_inline.rs
index 1af3b3e2c13..497f4a660ea 100644
--- a/compiler/rustc_mir_build/src/check_inline.rs
+++ b/compiler/rustc_mir_transform/src/check_inline.rs
@@ -1,3 +1,6 @@
+//! Check that a body annotated with `#[rustc_force_inline]` will not fail to inline based on its
+//! definition alone (irrespective of any specific caller).
+
 use rustc_attr_parsing::InlineAttr;
 use rustc_hir::def_id::DefId;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
@@ -6,30 +9,37 @@ use rustc_middle::ty;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::sym;
 
-/// Check that a body annotated with `#[rustc_force_inline]` will not fail to inline based on its
-/// definition alone (irrespective of any specific caller).
-pub(crate) fn check_force_inline<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
-    let def_id = body.source.def_id();
-    if !tcx.hir().body_owner_kind(def_id).is_fn_or_closure() || !def_id.is_local() {
-        return;
-    }
-    let InlineAttr::Force { attr_span, .. } = tcx.codegen_fn_attrs(def_id).inline else {
-        return;
-    };
+use crate::pass_manager::MirLint;
 
-    if let Err(reason) =
-        is_inline_valid_on_fn(tcx, def_id).and_then(|_| is_inline_valid_on_body(tcx, body))
-    {
-        tcx.dcx().emit_err(crate::errors::InvalidForceInline {
-            attr_span,
-            callee_span: tcx.def_span(def_id),
-            callee: tcx.def_path_str(def_id),
-            reason,
-        });
+pub(super) struct CheckForceInline;
+
+impl<'tcx> MirLint<'tcx> for CheckForceInline {
+    fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
+        let def_id = body.source.def_id();
+        if !tcx.hir().body_owner_kind(def_id).is_fn_or_closure() || !def_id.is_local() {
+            return;
+        }
+        let InlineAttr::Force { attr_span, .. } = tcx.codegen_fn_attrs(def_id).inline else {
+            return;
+        };
+
+        if let Err(reason) =
+            is_inline_valid_on_fn(tcx, def_id).and_then(|_| is_inline_valid_on_body(tcx, body))
+        {
+            tcx.dcx().emit_err(crate::errors::InvalidForceInline {
+                attr_span,
+                callee_span: tcx.def_span(def_id),
+                callee: tcx.def_path_str(def_id),
+                reason,
+            });
+        }
     }
 }
 
-pub fn is_inline_valid_on_fn<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Result<(), &'static str> {
+pub(super) fn is_inline_valid_on_fn<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+) -> Result<(), &'static str> {
     let codegen_attrs = tcx.codegen_fn_attrs(def_id);
     if tcx.has_attr(def_id, sym::rustc_no_mir_inline) {
         return Err("#[rustc_no_mir_inline]");
@@ -65,7 +75,7 @@ pub fn is_inline_valid_on_fn<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Result<(
     Ok(())
 }
 
-pub fn is_inline_valid_on_body<'tcx>(
+pub(super) fn is_inline_valid_on_body<'tcx>(
     _: TyCtxt<'tcx>,
     body: &Body<'tcx>,
 ) -> Result<(), &'static str> {
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index 1a9323329f6..8d397f63cc7 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -1,10 +1,9 @@
 use std::cmp::Ordering;
-use std::fmt::{self, Debug};
 
 use either::Either;
 use itertools::Itertools;
 use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_data_structures::graph::DirectedGraph;
 use rustc_index::IndexVec;
 use rustc_index::bit_set::DenseBitSet;
@@ -20,134 +19,163 @@ mod iter_nodes;
 mod node_flow;
 mod union_find;
 
-/// The coverage counter or counter expression associated with a particular
-/// BCB node or BCB edge.
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-enum BcbCounter {
-    Counter { id: CounterId },
-    Expression { id: ExpressionId },
+/// Ensures that each BCB node needing a counter has one, by creating physical
+/// counters or counter expressions for nodes as required.
+pub(super) fn make_bcb_counters(
+    graph: &CoverageGraph,
+    bcb_needs_counter: &DenseBitSet<BasicCoverageBlock>,
+) -> CoverageCounters {
+    // Create the derived graphs that are necessary for subsequent steps.
+    let balanced_graph = BalancedFlowGraph::for_graph(graph, |n| !graph[n].is_out_summable);
+    let merged_graph = MergedNodeFlowGraph::for_balanced_graph(&balanced_graph);
+
+    // Use those graphs to determine which nodes get physical counters, and how
+    // to compute the execution counts of other nodes from those counters.
+    let nodes = make_node_counter_priority_list(graph, balanced_graph);
+    let node_counters = merged_graph.make_node_counters(&nodes);
+
+    // Convert the counters into a form suitable for embedding into MIR.
+    transcribe_counters(&node_counters, bcb_needs_counter)
 }
 
-impl BcbCounter {
-    fn as_term(&self) -> CovTerm {
-        match *self {
-            BcbCounter::Counter { id, .. } => CovTerm::Counter(id),
-            BcbCounter::Expression { id, .. } => CovTerm::Expression(id),
-        }
-    }
+/// Arranges the nodes in `balanced_graph` into a list, such that earlier nodes
+/// take priority in being given a counter expression instead of a physical counter.
+fn make_node_counter_priority_list(
+    graph: &CoverageGraph,
+    balanced_graph: BalancedFlowGraph<&CoverageGraph>,
+) -> Vec<BasicCoverageBlock> {
+    // A "reloop" node has exactly one out-edge, which jumps back to the top
+    // of an enclosing loop. Reloop nodes are typically visited more times
+    // than loop-exit nodes, so try to avoid giving them physical counters.
+    let is_reloop_node = IndexVec::from_fn_n(
+        |node| match graph.successors[node].as_slice() {
+            &[succ] => graph.dominates(succ, node),
+            _ => false,
+        },
+        graph.num_nodes(),
+    );
+
+    let mut nodes = balanced_graph.iter_nodes().rev().collect::<Vec<_>>();
+    // The first node is the sink, which must not get a physical counter.
+    assert_eq!(nodes[0], balanced_graph.sink);
+    // Sort the real nodes, such that earlier (lesser) nodes take priority
+    // in being given a counter expression instead of a physical counter.
+    nodes[1..].sort_by(|&a, &b| {
+        // Start with a dummy `Equal` to make the actual tests line up nicely.
+        Ordering::Equal
+            // Prefer a physical counter for return/yield nodes.
+            .then_with(|| Ord::cmp(&graph[a].is_out_summable, &graph[b].is_out_summable))
+            // Prefer an expression for reloop nodes (see definition above).
+            .then_with(|| Ord::cmp(&is_reloop_node[a], &is_reloop_node[b]).reverse())
+            // Otherwise, prefer a physical counter for dominating nodes.
+            .then_with(|| graph.cmp_in_dominator_order(a, b).reverse())
+    });
+    nodes
 }
 
-impl Debug for BcbCounter {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            Self::Counter { id, .. } => write!(fmt, "Counter({:?})", id.index()),
-            Self::Expression { id } => write!(fmt, "Expression({:?})", id.index()),
+// Converts node counters into a form suitable for embedding into MIR.
+fn transcribe_counters(
+    old: &NodeCounters<BasicCoverageBlock>,
+    bcb_needs_counter: &DenseBitSet<BasicCoverageBlock>,
+) -> CoverageCounters {
+    let mut new = CoverageCounters::with_num_bcbs(bcb_needs_counter.domain_size());
+
+    for bcb in bcb_needs_counter.iter() {
+        // Our counter-creation algorithm doesn't guarantee that a counter
+        // expression starts or ends with a positive term, so partition the
+        // counters into "positive" and "negative" lists for easier handling.
+        let (mut pos, mut neg): (Vec<_>, Vec<_>) =
+            old.counter_expr(bcb).iter().partition_map(|&CounterTerm { node, op }| match op {
+                Op::Add => Either::Left(node),
+                Op::Subtract => Either::Right(node),
+            });
+
+        if pos.is_empty() {
+            // If we somehow end up with no positive terms, fall back to
+            // creating a physical counter. There's no known way for this
+            // to happen, but we can avoid an ICE if it does.
+            debug_assert!(false, "{bcb:?} has no positive counter terms");
+            pos = vec![bcb];
+            neg = vec![];
         }
-    }
-}
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-struct BcbExpression {
-    lhs: BcbCounter,
-    op: Op,
-    rhs: BcbCounter,
-}
+        // These intermediate sorts are not strictly necessary, but were helpful
+        // in reducing churn when switching to the current counter-creation scheme.
+        // They also help to slightly decrease the overall size of the expression
+        // table, due to more subexpressions being shared.
+        pos.sort();
+        neg.sort();
+
+        let mut new_counters_for_sites = |sites: Vec<BasicCoverageBlock>| {
+            sites.into_iter().map(|node| new.ensure_phys_counter(node)).collect::<Vec<_>>()
+        };
+        let mut pos = new_counters_for_sites(pos);
+        let mut neg = new_counters_for_sites(neg);
+
+        // These sorts are also not strictly necessary; see above.
+        pos.sort();
+        neg.sort();
+
+        let pos_counter = new.make_sum(&pos).expect("`pos` should not be empty");
+        let new_counter = new.make_subtracted_sum(pos_counter, &neg);
+        new.set_node_counter(bcb, new_counter);
+    }
 
-/// Enum representing either a node or an edge in the coverage graph.
-///
-/// FIXME(#135481): This enum is no longer needed now that we only instrument
-/// nodes and not edges. It can be removed in a subsequent PR.
-#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub(super) enum Site {
-    Node { bcb: BasicCoverageBlock },
+    new
 }
 
 /// Generates and stores coverage counter and coverage expression information
-/// associated with nodes/edges in the BCB graph.
+/// associated with nodes in the coverage graph.
 pub(super) struct CoverageCounters {
     /// List of places where a counter-increment statement should be injected
     /// into MIR, each with its corresponding counter ID.
-    counter_increment_sites: IndexVec<CounterId, Site>,
+    phys_counter_for_node: FxIndexMap<BasicCoverageBlock, CounterId>,
+    next_counter_id: CounterId,
 
     /// Coverage counters/expressions that are associated with individual BCBs.
-    node_counters: IndexVec<BasicCoverageBlock, Option<BcbCounter>>,
+    node_counters: IndexVec<BasicCoverageBlock, Option<CovTerm>>,
 
     /// Table of expression data, associating each expression ID with its
     /// corresponding operator (+ or -) and its LHS/RHS operands.
-    expressions: IndexVec<ExpressionId, BcbExpression>,
+    expressions: IndexVec<ExpressionId, Expression>,
     /// Remember expressions that have already been created (or simplified),
     /// so that we don't create unnecessary duplicates.
-    expressions_memo: FxHashMap<BcbExpression, BcbCounter>,
+    expressions_memo: FxHashMap<Expression, CovTerm>,
 }
 
 impl CoverageCounters {
-    /// Ensures that each BCB node needing a counter has one, by creating physical
-    /// counters or counter expressions for nodes and edges as required.
-    pub(super) fn make_bcb_counters(
-        graph: &CoverageGraph,
-        bcb_needs_counter: &DenseBitSet<BasicCoverageBlock>,
-    ) -> Self {
-        let balanced_graph = BalancedFlowGraph::for_graph(graph, |n| !graph[n].is_out_summable);
-        let merged_graph = MergedNodeFlowGraph::for_balanced_graph(&balanced_graph);
-
-        // A "reloop" node has exactly one out-edge, which jumps back to the top
-        // of an enclosing loop. Reloop nodes are typically visited more times
-        // than loop-exit nodes, so try to avoid giving them physical counters.
-        let is_reloop_node = IndexVec::from_fn_n(
-            |node| match graph.successors[node].as_slice() {
-                &[succ] => graph.dominates(succ, node),
-                _ => false,
-            },
-            graph.num_nodes(),
-        );
-
-        let mut nodes = balanced_graph.iter_nodes().rev().collect::<Vec<_>>();
-        // The first node is the sink, which must not get a physical counter.
-        assert_eq!(nodes[0], balanced_graph.sink);
-        // Sort the real nodes, such that earlier (lesser) nodes take priority
-        // in being given a counter expression instead of a physical counter.
-        nodes[1..].sort_by(|&a, &b| {
-            // Start with a dummy `Equal` to make the actual tests line up nicely.
-            Ordering::Equal
-                // Prefer a physical counter for return/yield nodes.
-                .then_with(|| Ord::cmp(&graph[a].is_out_summable, &graph[b].is_out_summable))
-                // Prefer an expression for reloop nodes (see definition above).
-                .then_with(|| Ord::cmp(&is_reloop_node[a], &is_reloop_node[b]).reverse())
-                // Otherwise, prefer a physical counter for dominating nodes.
-                .then_with(|| graph.cmp_in_dominator_order(a, b).reverse())
-        });
-        let node_counters = merged_graph.make_node_counters(&nodes);
-
-        Transcriber::new(graph.num_nodes(), node_counters).transcribe_counters(bcb_needs_counter)
-    }
-
     fn with_num_bcbs(num_bcbs: usize) -> Self {
         Self {
-            counter_increment_sites: IndexVec::new(),
+            phys_counter_for_node: FxIndexMap::default(),
+            next_counter_id: CounterId::ZERO,
             node_counters: IndexVec::from_elem_n(None, num_bcbs),
             expressions: IndexVec::new(),
             expressions_memo: FxHashMap::default(),
         }
     }
 
-    /// Creates a new physical counter for a BCB node or edge.
-    fn make_phys_counter(&mut self, site: Site) -> BcbCounter {
-        let id = self.counter_increment_sites.push(site);
-        BcbCounter::Counter { id }
+    /// Returns the physical counter for the given node, creating it if necessary.
+    fn ensure_phys_counter(&mut self, bcb: BasicCoverageBlock) -> CovTerm {
+        let id = *self.phys_counter_for_node.entry(bcb).or_insert_with(|| {
+            let id = self.next_counter_id;
+            self.next_counter_id = id + 1;
+            id
+        });
+        CovTerm::Counter(id)
     }
 
-    fn make_expression(&mut self, lhs: BcbCounter, op: Op, rhs: BcbCounter) -> BcbCounter {
-        let new_expr = BcbExpression { lhs, op, rhs };
-        *self.expressions_memo.entry(new_expr).or_insert_with(|| {
+    fn make_expression(&mut self, lhs: CovTerm, op: Op, rhs: CovTerm) -> CovTerm {
+        let new_expr = Expression { lhs, op, rhs };
+        *self.expressions_memo.entry(new_expr.clone()).or_insert_with(|| {
             let id = self.expressions.push(new_expr);
-            BcbCounter::Expression { id }
+            CovTerm::Expression(id)
         })
     }
 
     /// Creates a counter that is the sum of the given counters.
     ///
     /// Returns `None` if the given list of counters was empty.
-    fn make_sum(&mut self, counters: &[BcbCounter]) -> Option<BcbCounter> {
+    fn make_sum(&mut self, counters: &[CovTerm]) -> Option<CovTerm> {
         counters
             .iter()
             .copied()
@@ -155,16 +183,18 @@ impl CoverageCounters {
     }
 
     /// Creates a counter whose value is `lhs - SUM(rhs)`.
-    fn make_subtracted_sum(&mut self, lhs: BcbCounter, rhs: &[BcbCounter]) -> BcbCounter {
+    fn make_subtracted_sum(&mut self, lhs: CovTerm, rhs: &[CovTerm]) -> CovTerm {
         let Some(rhs_sum) = self.make_sum(rhs) else { return lhs };
         self.make_expression(lhs, Op::Subtract, rhs_sum)
     }
 
     pub(super) fn num_counters(&self) -> usize {
-        self.counter_increment_sites.len()
+        let num_counters = self.phys_counter_for_node.len();
+        assert_eq!(num_counters, self.next_counter_id.as_usize());
+        num_counters
     }
 
-    fn set_node_counter(&mut self, bcb: BasicCoverageBlock, counter: BcbCounter) -> BcbCounter {
+    fn set_node_counter(&mut self, bcb: BasicCoverageBlock, counter: CovTerm) -> CovTerm {
         let existing = self.node_counters[bcb].replace(counter);
         assert!(
             existing.is_none(),
@@ -174,16 +204,16 @@ impl CoverageCounters {
     }
 
     pub(super) fn term_for_bcb(&self, bcb: BasicCoverageBlock) -> Option<CovTerm> {
-        self.node_counters[bcb].map(|counter| counter.as_term())
+        self.node_counters[bcb]
     }
 
-    /// Returns an iterator over all the nodes/edges in the coverage graph that
+    /// Returns an iterator over all the nodes in the coverage graph that
     /// should have a counter-increment statement injected into MIR, along with
     /// each site's corresponding counter ID.
     pub(super) fn counter_increment_sites(
         &self,
-    ) -> impl Iterator<Item = (CounterId, Site)> + Captures<'_> {
-        self.counter_increment_sites.iter_enumerated().map(|(id, &site)| (id, site))
+    ) -> impl Iterator<Item = (CounterId, BasicCoverageBlock)> + Captures<'_> {
+        self.phys_counter_for_node.iter().map(|(&site, &id)| (id, site))
     }
 
     /// Returns an iterator over the subset of BCB nodes that have been associated
@@ -193,93 +223,13 @@ impl CoverageCounters {
     ) -> impl Iterator<Item = (BasicCoverageBlock, ExpressionId)> + Captures<'_> {
         self.node_counters.iter_enumerated().filter_map(|(bcb, &counter)| match counter {
             // Yield the BCB along with its associated expression ID.
-            Some(BcbCounter::Expression { id }) => Some((bcb, id)),
+            Some(CovTerm::Expression(id)) => Some((bcb, id)),
             // This BCB is associated with a counter or nothing, so skip it.
-            Some(BcbCounter::Counter { .. }) | None => None,
+            Some(CovTerm::Counter { .. } | CovTerm::Zero) | None => None,
         })
     }
 
     pub(super) fn into_expressions(self) -> IndexVec<ExpressionId, Expression> {
-        let old_len = self.expressions.len();
-        let expressions = self
-            .expressions
-            .into_iter()
-            .map(|BcbExpression { lhs, op, rhs }| Expression {
-                lhs: lhs.as_term(),
-                op,
-                rhs: rhs.as_term(),
-            })
-            .collect::<IndexVec<ExpressionId, _>>();
-
-        // Expression IDs are indexes into this vector, so make sure we didn't
-        // accidentally invalidate them by changing its length.
-        assert_eq!(old_len, expressions.len());
-        expressions
-    }
-}
-
-struct Transcriber {
-    old: NodeCounters<BasicCoverageBlock>,
-    new: CoverageCounters,
-    phys_counter_for_site: FxHashMap<Site, BcbCounter>,
-}
-
-impl Transcriber {
-    fn new(num_nodes: usize, old: NodeCounters<BasicCoverageBlock>) -> Self {
-        Self {
-            old,
-            new: CoverageCounters::with_num_bcbs(num_nodes),
-            phys_counter_for_site: FxHashMap::default(),
-        }
-    }
-
-    fn transcribe_counters(
-        mut self,
-        bcb_needs_counter: &DenseBitSet<BasicCoverageBlock>,
-    ) -> CoverageCounters {
-        for bcb in bcb_needs_counter.iter() {
-            let site = Site::Node { bcb };
-            let (mut pos, mut neg): (Vec<_>, Vec<_>) =
-                self.old.counter_expr(bcb).iter().partition_map(
-                    |&CounterTerm { node, op }| match op {
-                        Op::Add => Either::Left(node),
-                        Op::Subtract => Either::Right(node),
-                    },
-                );
-
-            if pos.is_empty() {
-                // If we somehow end up with no positive terms, fall back to
-                // creating a physical counter. There's no known way for this
-                // to happen, but we can avoid an ICE if it does.
-                debug_assert!(false, "{site:?} has no positive counter terms");
-                pos = vec![bcb];
-                neg = vec![];
-            }
-
-            pos.sort();
-            neg.sort();
-
-            let mut new_counters_for_sites = |sites: Vec<BasicCoverageBlock>| {
-                sites
-                    .into_iter()
-                    .map(|node| self.ensure_phys_counter(Site::Node { bcb: node }))
-                    .collect::<Vec<_>>()
-            };
-            let mut pos = new_counters_for_sites(pos);
-            let mut neg = new_counters_for_sites(neg);
-
-            pos.sort();
-            neg.sort();
-
-            let pos_counter = self.new.make_sum(&pos).expect("`pos` should not be empty");
-            let new_counter = self.new.make_subtracted_sum(pos_counter, &neg);
-            self.new.set_node_counter(bcb, new_counter);
-        }
-
-        self.new
-    }
-
-    fn ensure_phys_counter(&mut self, site: Site) -> BcbCounter {
-        *self.phys_counter_for_site.entry(site).or_insert_with(|| self.new.make_phys_counter(site))
+        self.expressions
     }
 }
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index 25dc7f31227..392b54c8d81 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -135,7 +135,7 @@ impl CoverageGraph {
                 bb_to_bcb[bb] = Some(bcb);
             }
 
-            let is_out_summable = basic_blocks.last().map_or(false, |&bb| {
+            let is_out_summable = basic_blocks.last().is_some_and(|&bb| {
                 bcb_filtered_successors(mir_body[bb].terminator()).is_out_summable()
             });
             let bcb_data = BasicCoverageBlockData { basic_blocks, is_out_summable };
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index b1b609595b7..19568735df7 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -21,7 +21,7 @@ use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
 use tracing::{debug, debug_span, trace};
 
-use crate::coverage::counters::{CoverageCounters, Site};
+use crate::coverage::counters::CoverageCounters;
 use crate::coverage::graph::CoverageGraph;
 use crate::coverage::mappings::ExtractedMappings;
 
@@ -89,8 +89,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
         return;
     }
 
-    let coverage_counters =
-        CoverageCounters::make_bcb_counters(&graph, &bcbs_with_counter_mappings);
+    let coverage_counters = counters::make_bcb_counters(&graph, &bcbs_with_counter_mappings);
 
     let mappings = create_mappings(&extracted_mappings, &coverage_counters);
     if mappings.is_empty() {
@@ -239,14 +238,8 @@ fn inject_coverage_statements<'tcx>(
     coverage_counters: &CoverageCounters,
 ) {
     // Inject counter-increment statements into MIR.
-    for (id, site) in coverage_counters.counter_increment_sites() {
-        // Determine the block to inject a counter-increment statement into.
-        // For BCB nodes this is just their first block, but for edges we need
-        // to create a new block between the two BCBs, and inject into that.
-        let target_bb = match site {
-            Site::Node { bcb } => graph[bcb].leader_bb(),
-        };
-
+    for (id, bcb) in coverage_counters.counter_increment_sites() {
+        let target_bb = graph[bcb].leader_bb();
         inject_statement(mir_body, CoverageKind::CounterIncrement { id }, target_bb);
     }
 
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index cc44114782c..51af77778af 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -408,6 +408,18 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
         state: &mut State<FlatSet<Scalar>>,
     ) -> ValueOrPlace<FlatSet<Scalar>> {
         let val = match rvalue {
+            Rvalue::Len(place) => {
+                let place_ty = place.ty(self.local_decls, self.tcx);
+                if let ty::Array(_, len) = place_ty.ty.kind() {
+                    Const::Ty(self.tcx.types.usize, *len)
+                        .try_eval_scalar(self.tcx, self.typing_env)
+                        .map_or(FlatSet::Top, FlatSet::Elem)
+                } else if let [ProjectionElem::Deref] = place.projection[..] {
+                    state.get_len(place.local.into(), &self.map)
+                } else {
+                    FlatSet::Top
+                }
+            }
             Rvalue::Cast(CastKind::IntToInt | CastKind::IntToFloat, operand, ty) => {
                 let Ok(layout) = self.tcx.layout_of(self.typing_env.as_query_input(*ty)) else {
                     return ValueOrPlace::Value(FlatSet::Top);
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index 1ac4d835946..b4f9f1f08ef 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -575,6 +575,7 @@ impl WriteInfo {
                     | Rvalue::NullaryOp(_, _)
                     | Rvalue::Ref(_, _, _)
                     | Rvalue::RawPtr(_, _)
+                    | Rvalue::Len(_)
                     | Rvalue::Discriminant(_)
                     | Rvalue::CopyForDeref(_) => {}
                 }
diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs
index 015633d145f..a2fd46043ca 100644
--- a/compiler/rustc_mir_transform/src/errors.rs
+++ b/compiler/rustc_mir_transform/src/errors.rs
@@ -10,6 +10,28 @@ use rustc_span::{Span, Symbol};
 use crate::fluent_generated as fluent;
 
 #[derive(LintDiagnostic)]
+#[diag(mir_transform_unconditional_recursion)]
+#[help]
+pub(crate) struct UnconditionalRecursion {
+    #[label]
+    pub(crate) span: Span,
+    #[label(mir_transform_unconditional_recursion_call_site_label)]
+    pub(crate) call_sites: Vec<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_transform_force_inline_attr)]
+#[note]
+pub(crate) struct InvalidForceInline {
+    #[primary_span]
+    pub attr_span: Span,
+    #[label(mir_transform_callee)]
+    pub callee_span: Span,
+    pub callee: String,
+    pub reason: &'static str,
+}
+
+#[derive(LintDiagnostic)]
 pub(crate) enum ConstMutate {
     #[diag(mir_transform_const_modify)]
     #[note]
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index affc4cf0afc..cb03b422d9e 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -223,6 +223,8 @@ enum Value<'tcx> {
     Projection(VnIndex, ProjectionElem<VnIndex, Ty<'tcx>>),
     /// Discriminant of the given value.
     Discriminant(VnIndex),
+    /// Length of an array or slice.
+    Len(VnIndex),
 
     // Operations.
     NullaryOp(NullOp<'tcx>, Ty<'tcx>),
@@ -511,6 +513,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                     self.ecx.discriminant_for_variant(base.layout.ty, variant).discard_err()?;
                 discr_value.into()
             }
+            Len(slice) => {
+                let slice = self.evaluated[slice].as_ref()?;
+                let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap();
+                let len = slice.len(&self.ecx).discard_err()?;
+                let imm = ImmTy::from_uint(len, usize_layout);
+                imm.into()
+            }
             NullaryOp(null_op, ty) => {
                 let layout = self.ecx.layout_of(ty).ok()?;
                 if let NullOp::SizeOf | NullOp::AlignOf = null_op
@@ -854,6 +863,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             }
 
             // Operations.
+            Rvalue::Len(ref mut place) => return self.simplify_len(place, location),
             Rvalue::Cast(ref mut kind, ref mut value, to) => {
                 return self.simplify_cast(kind, value, to, location);
             }
@@ -1474,6 +1484,47 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         Some(self.insert(Value::Cast { kind: *kind, value, from, to }))
     }
 
+    fn simplify_len(&mut self, place: &mut Place<'tcx>, location: Location) -> Option<VnIndex> {
+        // Trivial case: we are fetching a statically known length.
+        let place_ty = place.ty(self.local_decls, self.tcx).ty;
+        if let ty::Array(_, len) = place_ty.kind() {
+            return self.insert_constant(Const::from_ty_const(
+                *len,
+                self.tcx.types.usize,
+                self.tcx,
+            ));
+        }
+
+        let mut inner = self.simplify_place_value(place, location)?;
+
+        // The length information is stored in the wide pointer.
+        // Reborrowing copies length information from one pointer to the other.
+        while let Value::Address { place: borrowed, .. } = self.get(inner)
+            && let [PlaceElem::Deref] = borrowed.projection[..]
+            && let Some(borrowed) = self.locals[borrowed.local]
+        {
+            inner = borrowed;
+        }
+
+        // We have an unsizing cast, which assigns the length to wide pointer metadata.
+        if let Value::Cast { kind, from, to, .. } = self.get(inner)
+            && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) = kind
+            && let Some(from) = from.builtin_deref(true)
+            && let ty::Array(_, len) = from.kind()
+            && let Some(to) = to.builtin_deref(true)
+            && let ty::Slice(..) = to.kind()
+        {
+            return self.insert_constant(Const::from_ty_const(
+                *len,
+                self.tcx.types.usize,
+                self.tcx,
+            ));
+        }
+
+        // Fallback: a symbolic `Len`.
+        Some(self.insert(Value::Len(inner)))
+    }
+
     fn pointers_have_same_metadata(&self, left_ptr_ty: Ty<'tcx>, right_ptr_ty: Ty<'tcx>) -> bool {
         let left_meta_ty = left_ptr_ty.pointee_metadata_ty_or_projection(self.tcx);
         let right_meta_ty = right_ptr_ty.pointee_metadata_ty_or_projection(self.tcx);
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 470393c9ae1..2052e28325c 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -21,8 +21,8 @@ use tracing::{debug, instrument, trace, trace_span};
 use crate::cost_checker::CostChecker;
 use crate::deref_separator::deref_finder;
 use crate::simplify::simplify_cfg;
-use crate::util;
 use crate::validate::validate_types;
+use crate::{check_inline, util};
 
 pub(crate) mod cycle;
 
@@ -575,7 +575,7 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>(
     check_mir_is_available(inliner, caller_body, callsite.callee)?;
 
     let callee_attrs = tcx.codegen_fn_attrs(callsite.callee.def_id());
-    rustc_mir_build::check_inline::is_inline_valid_on_fn(tcx, callsite.callee.def_id())?;
+    check_inline::is_inline_valid_on_fn(tcx, callsite.callee.def_id())?;
     check_codegen_attributes(inliner, callsite, callee_attrs)?;
 
     let terminator = caller_body[callsite.block].terminator.as_ref().unwrap();
@@ -590,7 +590,7 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>(
     }
 
     let callee_body = try_instance_mir(tcx, callsite.callee.def)?;
-    rustc_mir_build::check_inline::is_inline_valid_on_body(tcx, callee_body)?;
+    check_inline::is_inline_valid_on_body(tcx, callee_body)?;
     inliner.check_callee_mir_body(callsite, callee_body, callee_attrs)?;
 
     let Ok(callee_body) = callsite.callee.try_instantiate_mir_and_normalize_erasing_regions(
diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index 20e2e3e8ba2..5a36519e6a3 100644
--- a/compiler/rustc_mir_transform/src/instsimplify.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -46,6 +46,7 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
                         }
                         ctx.simplify_bool_cmp(rvalue);
                         ctx.simplify_ref_deref(rvalue);
+                        ctx.simplify_len(rvalue);
                         ctx.simplify_ptr_aggregate(rvalue);
                         ctx.simplify_cast(rvalue);
                         ctx.simplify_repeated_aggregate(rvalue);
@@ -161,6 +162,18 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
         }
     }
 
+    /// Transform `Len([_; N])` ==> `N`.
+    fn simplify_len(&self, rvalue: &mut Rvalue<'tcx>) {
+        if let Rvalue::Len(ref place) = *rvalue {
+            let place_ty = place.ty(self.local_decls, self.tcx).ty;
+            if let ty::Array(_, len) = *place_ty.kind() {
+                let const_ = Const::from_ty_const(len, self.tcx.types.usize, self.tcx);
+                let constant = ConstOperand { span: DUMMY_SP, const_, user_ty: None };
+                *rvalue = Rvalue::Use(Operand::Constant(Box::new(constant)));
+            }
+        }
+    }
+
     /// Transform `Aggregate(RawPtr, [p, ()])` ==> `Cast(PtrToPtr, p)`.
     fn simplify_ptr_aggregate(&self, rvalue: &mut Rvalue<'tcx>) {
         if let Rvalue::Aggregate(box AggregateKind::RawPtr(pointee_ty, mutability), fields) = rvalue
diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs
index 9b3a0e67295..f4ac5c6aa80 100644
--- a/compiler/rustc_mir_transform/src/known_panics_lint.rs
+++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs
@@ -440,6 +440,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             | Rvalue::Use(..)
             | Rvalue::CopyForDeref(..)
             | Rvalue::Repeat(..)
+            | Rvalue::Len(..)
             | Rvalue::Cast(..)
             | Rvalue::ShallowInitBox(..)
             | Rvalue::Discriminant(..)
@@ -599,6 +600,20 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                 return None;
             }
 
+            Len(place) => {
+                let len = if let ty::Array(_, n) = place.ty(self.local_decls(), self.tcx).ty.kind()
+                {
+                    n.try_to_target_usize(self.tcx)?
+                } else {
+                    match self.get_const(place)? {
+                        Value::Immediate(src) => src.len(&self.ecx).discard_err()?,
+                        Value::Aggregate { fields, .. } => fields.len() as u64,
+                        Value::Uninit => return None,
+                    }
+                };
+                ImmTy::from_scalar(Scalar::from_target_usize(len, self), layout).into()
+            }
+
             Ref(..) | RawPtr(..) => return None,
 
             NullaryOp(ref null_op, ty) => {
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index db999bea986..d1bacf1f598 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -114,6 +114,8 @@ declare_passes! {
     mod add_moves_for_packed_drops : AddMovesForPackedDrops;
     mod add_retag : AddRetag;
     mod add_subtyping_projections : Subtyper;
+    mod check_inline : CheckForceInline;
+    mod check_call_recursion : CheckCallRecursion, CheckDropRecursion;
     mod check_alignment : CheckAlignment;
     mod check_const_item_mutation : CheckConstItemMutation;
     mod check_packed_ref : CheckPackedRef;
@@ -375,6 +377,8 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
         &mut body,
         &[
             // MIR-level lints.
+            &Lint(check_inline::CheckForceInline),
+            &Lint(check_call_recursion::CheckCallRecursion),
             &Lint(check_packed_ref::CheckPackedRef),
             &Lint(check_const_item_mutation::CheckConstItemMutation),
             &Lint(function_item_references::FunctionItemReferences),
@@ -505,10 +509,6 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
 
     run_analysis_to_runtime_passes(tcx, &mut body);
 
-    // Now that drop elaboration has been performed, we can check for
-    // unconditional drop recursion.
-    rustc_mir_build::lints::check_drop_recursion(tcx, &body);
-
     tcx.alloc_steal_mir(body)
 }
 
@@ -570,6 +570,8 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // Calling this after `PostAnalysisNormalize` ensures that we don't deal with opaque types.
         &add_subtyping_projections::Subtyper,
         &elaborate_drops::ElaborateDrops,
+        // Needs to happen after drop elaboration.
+        &Lint(check_call_recursion::CheckDropRecursion),
         // This will remove extraneous landing pads which are no longer
         // necessary as well as forcing any call in a non-unwinding
         // function calling a possibly-unwinding function to abort the process.
diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs
index 7451f419304..6be95b1f0f1 100644
--- a/compiler/rustc_mir_transform/src/promote_consts.rs
+++ b/compiler/rustc_mir_transform/src/promote_consts.rs
@@ -430,7 +430,9 @@ impl<'tcx> Validator<'_, 'tcx> {
                 self.validate_operand(op)?
             }
 
-            Rvalue::Discriminant(place) => self.validate_place(place.as_ref())?,
+            Rvalue::Discriminant(place) | Rvalue::Len(place) => {
+                self.validate_place(place.as_ref())?
+            }
 
             Rvalue::ThreadLocalRef(_) => return Err(Unpromotable),
 
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index 414477d9004..b62e34ac08d 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -1018,6 +1018,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                 }
             }
             Rvalue::Ref(..) => {}
+            Rvalue::Len(p) => {
+                let pty = p.ty(&self.body.local_decls, self.tcx).ty;
+                check_kinds!(
+                    pty,
+                    "Cannot compute length of non-array type {:?}",
+                    ty::Array(..) | ty::Slice(..)
+                );
+            }
             Rvalue::BinaryOp(op, vals) => {
                 use BinOp::*;
                 let a = vals.0.ty(&self.body.local_decls, self.tcx);
@@ -1116,6 +1124,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                         );
                     }
                     UnOp::PtrMetadata => {
+                        if !matches!(self.body.phase, MirPhase::Runtime(_)) {
+                            // It would probably be fine to support this in earlier phases, but at
+                            // the time of writing it's only ever introduced from intrinsic
+                            // lowering or other runtime-phase optimization passes, so earlier
+                            // things can just `bug!` on it.
+                            self.fail(location, "PtrMetadata should be in runtime MIR only");
+                        }
+
                         check_kinds!(
                             a,
                             "Cannot PtrMetadata non-pointer non-reference type {:?}",
diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml
index f9168112216..451c215566b 100644
--- a/compiler/rustc_next_trait_solver/Cargo.toml
+++ b/compiler/rustc_next_trait_solver/Cargo.toml
@@ -13,7 +13,6 @@ rustc_macros = { path = "../rustc_macros", optional = true }
 rustc_serialize = { path = "../rustc_serialize", optional = true }
 rustc_type_ir = { path = "../rustc_type_ir", default-features = false }
 rustc_type_ir_macros = { path = "../rustc_type_ir_macros" }
-smallvec = "1.8.1"
 tracing = "0.1"
 # tidy-alphabetical-end
 
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index 8a54a4ece98..62a7c84bc28 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -273,7 +273,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
                         //
                         // For this we set `next_orig_uv` to the next smallest, not yet compressed,
                         // universe of the input.
-                        if next_orig_uv.map_or(true, |curr_next_uv| uv.cannot_name(curr_next_uv)) {
+                        if next_orig_uv.is_none_or(|curr_next_uv| uv.cannot_name(curr_next_uv)) {
                             next_orig_uv = Some(uv);
                         }
                     }
diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs
index 37678bfd880..8d1194ee539 100644
--- a/compiler/rustc_next_trait_solver/src/solve/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs
@@ -277,23 +277,7 @@ where
         param_env: I::ParamEnv,
         ty: I::Ty,
     ) -> Result<I::Ty, NoSolution> {
-        if let ty::Alias(..) = ty.kind() {
-            let normalized_ty = self.next_ty_infer();
-            let alias_relate_goal = Goal::new(
-                self.cx(),
-                param_env,
-                ty::PredicateKind::AliasRelate(
-                    ty.into(),
-                    normalized_ty.into(),
-                    ty::AliasRelationDirection::Equate,
-                ),
-            );
-            self.add_goal(GoalSource::Misc, alias_relate_goal);
-            self.try_evaluate_added_goals()?;
-            Ok(self.resolve_vars_if_possible(normalized_ty))
-        } else {
-            Ok(ty)
-        }
+        self.structurally_normalize_term(param_env, ty.into()).map(|term| term.expect_ty())
     }
 
     /// Normalize a const for when it is structurally matched on, or more likely
@@ -308,22 +292,34 @@ where
         param_env: I::ParamEnv,
         ct: I::Const,
     ) -> Result<I::Const, NoSolution> {
-        if let ty::ConstKind::Unevaluated(..) = ct.kind() {
-            let normalized_ct = self.next_const_infer();
+        self.structurally_normalize_term(param_env, ct.into()).map(|term| term.expect_const())
+    }
+
+    /// Normalize a term for when it is structurally matched on.
+    ///
+    /// This function is necessary in nearly all cases before matching on a ty/const.
+    /// Not doing so is likely to be incomplete and therefore unsound during coherence.
+    fn structurally_normalize_term(
+        &mut self,
+        param_env: I::ParamEnv,
+        term: I::Term,
+    ) -> Result<I::Term, NoSolution> {
+        if let Some(_) = term.to_alias_term() {
+            let normalized_term = self.next_term_infer_of_kind(term);
             let alias_relate_goal = Goal::new(
                 self.cx(),
                 param_env,
                 ty::PredicateKind::AliasRelate(
-                    ct.into(),
-                    normalized_ct.into(),
+                    term,
+                    normalized_term,
                     ty::AliasRelationDirection::Equate,
                 ),
             );
             self.add_goal(GoalSource::Misc, alias_relate_goal);
             self.try_evaluate_added_goals()?;
-            Ok(self.resolve_vars_if_possible(normalized_ct))
+            Ok(self.resolve_vars_if_possible(normalized_term))
         } else {
-            Ok(ct)
+            Ok(term)
         }
     }
 
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 4faa243c02a..513fc9355c8 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -8,7 +8,6 @@ use rustc_type_ir::lang_items::TraitSolverLangItem;
 use rustc_type_ir::solve::CanonicalResponse;
 use rustc_type_ir::visit::TypeVisitableExt as _;
 use rustc_type_ir::{self as ty, Interner, TraitPredicate, TypingMode, Upcast as _, elaborate};
-use smallvec::SmallVec;
 use tracing::{instrument, trace};
 
 use crate::delegate::SolverDelegate;
@@ -1199,33 +1198,42 @@ where
         // nested requirements, over all others. This is a fix for #53123 and
         // prevents where-bounds from accidentally extending the lifetime of a
         // variable.
-        if candidates
-            .iter()
-            .any(|c| matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial)))
-        {
-            let trivial_builtin_impls: SmallVec<[_; 1]> = candidates
-                .iter()
-                .filter(|c| {
-                    matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial))
-                })
-                .map(|c| c.result)
-                .collect();
+        let mut trivial_builtin_impls = candidates.iter().filter(|c| {
+            matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial))
+        });
+        if let Some(candidate) = trivial_builtin_impls.next() {
             // There should only ever be a single trivial builtin candidate
             // as they would otherwise overlap.
-            assert_eq!(trivial_builtin_impls.len(), 1);
-            return if let Some(response) = self.try_merge_responses(&trivial_builtin_impls) {
-                Ok((response, Some(TraitGoalProvenVia::Misc)))
-            } else {
-                Ok((self.bail_with_ambiguity(&trivial_builtin_impls), None))
-            };
+            assert!(trivial_builtin_impls.next().is_none());
+            return Ok((candidate.result, Some(TraitGoalProvenVia::Misc)));
         }
 
         // If there are non-global where-bounds, prefer where-bounds
         // (including global ones) over everything else.
         let has_non_global_where_bounds = candidates.iter().any(|c| match c.source {
             CandidateSource::ParamEnv(idx) => {
-                let where_bound = goal.param_env.caller_bounds().get(idx);
-                where_bound.has_bound_vars() || !where_bound.is_global()
+                let where_bound = goal.param_env.caller_bounds().get(idx).unwrap();
+                let ty::ClauseKind::Trait(trait_pred) = where_bound.kind().skip_binder() else {
+                    unreachable!("expected trait-bound: {where_bound:?}");
+                };
+
+                if trait_pred.has_bound_vars() || !trait_pred.is_global() {
+                    return true;
+                }
+
+                // We don't consider a trait-bound global if it has a projection bound.
+                //
+                // See ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs
+                // for an example where this is necessary.
+                for p in goal.param_env.caller_bounds().iter() {
+                    if let ty::ClauseKind::Projection(proj) = p.kind().skip_binder() {
+                        if proj.projection_term.trait_ref(self.cx()) == trait_pred.trait_ref {
+                            return true;
+                        }
+                    }
+                }
+
+                false
             }
             _ => false,
         });
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index f963a424a7f..e681987ff07 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -11,18 +11,21 @@
 #![feature(if_let_guard)]
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
+#![feature(string_from_utf8_lossy_owned)]
 #![warn(unreachable_pub)]
 // tidy-alphabetical-end
 
-use std::path::Path;
+use std::path::{Path, PathBuf};
+use std::str::Utf8Error;
 
 use rustc_ast as ast;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::{AttrItem, Attribute, MetaItemInner, token};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::{Diag, FatalError, PResult};
+use rustc_errors::{Diag, EmissionGuarantee, FatalError, PResult, pluralize};
 use rustc_session::parse::ParseSess;
+use rustc_span::source_map::SourceMap;
 use rustc_span::{FileName, SourceFile, Span};
 pub use unicode_normalization::UNICODE_VERSION as UNICODE_NORMALIZATION_VERSION;
 
@@ -73,9 +76,22 @@ pub fn new_parser_from_file<'a>(
     path: &Path,
     sp: Option<Span>,
 ) -> Result<Parser<'a>, Vec<Diag<'a>>> {
-    let source_file = psess.source_map().load_file(path).unwrap_or_else(|e| {
-        let msg = format!("couldn't read {}: {}", path.display(), e);
+    let sm = psess.source_map();
+    let source_file = sm.load_file(path).unwrap_or_else(|e| {
+        let msg = format!("couldn't read `{}`: {}", path.display(), e);
         let mut err = psess.dcx().struct_fatal(msg);
+        if let Ok(contents) = std::fs::read(path)
+            && let Err(utf8err) = String::from_utf8(contents.clone())
+        {
+            utf8_error(
+                sm,
+                &path.display().to_string(),
+                sp,
+                &mut err,
+                utf8err.utf8_error(),
+                &contents,
+            );
+        }
         if let Some(sp) = sp {
             err.span(sp);
         }
@@ -84,6 +100,49 @@ pub fn new_parser_from_file<'a>(
     new_parser_from_source_file(psess, source_file)
 }
 
+pub fn utf8_error<E: EmissionGuarantee>(
+    sm: &SourceMap,
+    path: &str,
+    sp: Option<Span>,
+    err: &mut Diag<'_, E>,
+    utf8err: Utf8Error,
+    contents: &[u8],
+) {
+    // The file exists, but it wasn't valid UTF-8.
+    let start = utf8err.valid_up_to();
+    let note = format!("invalid utf-8 at byte `{start}`");
+    let msg = if let Some(len) = utf8err.error_len() {
+        format!(
+            "byte{s} `{bytes}` {are} not valid utf-8",
+            bytes = if len == 1 {
+                format!("{:?}", contents[start])
+            } else {
+                format!("{:?}", &contents[start..start + len])
+            },
+            s = pluralize!(len),
+            are = if len == 1 { "is" } else { "are" },
+        )
+    } else {
+        note.clone()
+    };
+    let contents = String::from_utf8_lossy(contents).to_string();
+    let source = sm.new_source_file(PathBuf::from(path).into(), contents);
+    let span = Span::with_root_ctxt(
+        source.normalized_byte_pos(start as u32),
+        source.normalized_byte_pos(start as u32),
+    );
+    if span.is_dummy() {
+        err.note(note);
+    } else {
+        if sp.is_some() {
+            err.span_note(span, msg);
+        } else {
+            err.span(span);
+            err.span_label(span, msg);
+        }
+    }
+}
+
 /// Given a session and a `source_file`, return a parser. Returns any buffered errors from lexing
 /// the initial token stream.
 fn new_parser_from_source_file(
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 7533e75ffe2..5cd02128287 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -2095,7 +2095,7 @@ impl<'a> Parser<'a> {
                     // point literal here, since there's no use of the exponent
                     // syntax that also constitutes a valid integer, so we need
                     // not check for that.
-                    if suffix.map_or(true, |s| s == sym::f32 || s == sym::f64)
+                    if suffix.is_none_or(|s| s == sym::f32 || s == sym::f64)
                         && symbol.as_str().chars().all(|c| c.is_numeric() || c == '_')
                         && self.token.span.hi() == next_token.span.lo()
                     {
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 8b6b37c0f8f..86f673c100c 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -11,7 +11,7 @@ use rustc_session::errors::report_lit_error;
 use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::lint::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNSAFE_ATTR_OUTSIDE_UNSAFE};
 use rustc_session::parse::ParseSess;
-use rustc_span::{BytePos, Span, Symbol, sym};
+use rustc_span::{Span, Symbol, sym};
 
 use crate::{errors, parse_in};
 
@@ -164,11 +164,7 @@ pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr:
             // wrapping it in `unsafe(...)`. Otherwise, we suggest putting the
             // `unsafe(`, `)` right after and right before the opening and closing
             // square bracket respectively.
-            let diag_span = if attr_item.span().can_be_used_for_suggestions() {
-                attr_item.span()
-            } else {
-                attr.span.with_lo(attr.span.lo() + BytePos(2)).with_hi(attr.span.hi() - BytePos(1))
-            };
+            let diag_span = attr_item.span();
 
             if attr.span.at_least_rust_2024() {
                 psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe {
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 9eb335cb34c..5418f054beb 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -514,13 +514,7 @@ impl<'a> Parser<'a> {
 
     /// Consumes all whitespace characters until the first non-whitespace character
     fn ws(&mut self) {
-        while let Some(&(_, c)) = self.cur.peek() {
-            if c.is_whitespace() {
-                self.cur.next();
-            } else {
-                break;
-            }
-        }
+        while let Some(_) = self.cur.next_if(|&(_, c)| c.is_whitespace()) {}
     }
 
     /// Parses all of a string which is to be considered a "raw literal" in a
@@ -545,7 +539,7 @@ impl<'a> Parser<'a> {
                 }
             }
         }
-        &self.input[start..self.input.len()]
+        &self.input[start..]
     }
 
     /// Parses an `Argument` structure, or what's contained within braces inside the format string.
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 3ed600a717f..133d84572e6 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -502,11 +502,6 @@ passes_multiple_rustc_main =
     .first = first `#[rustc_main]` function
     .additional = additional `#[rustc_main]` function
 
-passes_multiple_start_functions =
-    multiple `start` functions
-    .label = multiple `start` functions
-    .previous = previous `#[start]` function here
-
 passes_must_not_suspend =
     `must_not_suspend` attribute should be applied to a struct, enum, union, or trait
     .label = is not a struct, enum, union, or trait
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 1b2b8ac5dd9..dbb87443eed 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -275,7 +275,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     | sym::lang
                     | sym::needs_allocator
                     | sym::default_lib_allocator
-                    | sym::start
                     | sym::custom_mir,
                     ..
                 ] => {}
@@ -2655,7 +2654,6 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
         sym::repr,
         sym::path,
         sym::automatically_derived,
-        sym::start,
         sym::rustc_main,
         sym::derive,
         sym::test,
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index c5dc8e68fe8..34deb854e0f 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -1231,7 +1231,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
                     continue;
                 }
 
-                let is_positional = variant.fields.raw.first().map_or(false, |field| {
+                let is_positional = variant.fields.raw.first().is_some_and(|field| {
                     field.name.as_str().starts_with(|c: char| c.is_ascii_digit())
                 });
                 let report_on =
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index 4949a4316a7..22291c9282d 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -10,9 +10,7 @@ use rustc_session::RemapFileNameExt;
 use rustc_session::config::{CrateType, EntryFnType, RemapPathScopeComponents, sigpipe};
 use rustc_span::{Span, Symbol, sym};
 
-use crate::errors::{
-    AttrOnlyInFunctions, ExternMain, MultipleRustcMain, MultipleStartFunctions, NoMainErr,
-};
+use crate::errors::{AttrOnlyInFunctions, ExternMain, MultipleRustcMain, NoMainErr};
 
 struct EntryContext<'tcx> {
     tcx: TyCtxt<'tcx>,
@@ -20,9 +18,6 @@ struct EntryContext<'tcx> {
     /// The function has the `#[rustc_main]` attribute.
     rustc_main_fn: Option<(LocalDefId, Span)>,
 
-    /// The function that has the attribute `#[start]` on it.
-    start_fn: Option<(LocalDefId, Span)>,
-
     /// The functions that one might think are `main` but aren't, e.g.
     /// main functions not defined at the top level. For diagnostics.
     non_main_fns: Vec<Span>,
@@ -40,8 +35,7 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
         return None;
     }
 
-    let mut ctxt =
-        EntryContext { tcx, rustc_main_fn: None, start_fn: None, non_main_fns: Vec::new() };
+    let mut ctxt = EntryContext { tcx, rustc_main_fn: None, non_main_fns: Vec::new() };
 
     for id in tcx.hir().items() {
         check_and_search_item(id, &mut ctxt);
@@ -57,7 +51,7 @@ fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Opti
 
 fn check_and_search_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
     if !matches!(ctxt.tcx.def_kind(id.owner_id), DefKind::Fn) {
-        for attr in [sym::start, sym::rustc_main] {
+        for attr in [sym::rustc_main] {
             if let Some(span) = attr_span_by_symbol(ctxt, id, attr) {
                 ctxt.tcx.dcx().emit_err(AttrOnlyInFunctions { span, attr });
             }
@@ -91,24 +85,11 @@ fn check_and_search_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
                 });
             }
         }
-        EntryPointType::Start => {
-            if ctxt.start_fn.is_none() {
-                ctxt.start_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id)));
-            } else {
-                ctxt.tcx.dcx().emit_err(MultipleStartFunctions {
-                    span: ctxt.tcx.def_span(id.owner_id),
-                    labeled: ctxt.tcx.def_span(id.owner_id.to_def_id()),
-                    previous: ctxt.start_fn.unwrap().1,
-                });
-            }
-        }
     }
 }
 
 fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, EntryFnType)> {
-    if let Some((def_id, _)) = visitor.start_fn {
-        Some((def_id.to_def_id(), EntryFnType::Start))
-    } else if let Some((local_def_id, _)) = visitor.rustc_main_fn {
+    if let Some((local_def_id, _)) = visitor.rustc_main_fn {
         let def_id = local_def_id.to_def_id();
         Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx) }))
     } else {
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index c3043ac60aa..3d38b00e99f 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1314,17 +1314,6 @@ pub(crate) struct MultipleRustcMain {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_multiple_start_functions, code = E0138)]
-pub(crate) struct MultipleStartFunctions {
-    #[primary_span]
-    pub span: Span,
-    #[label]
-    pub labeled: Span,
-    #[label(passes_previous)]
-    pub previous: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(passes_extern_main)]
 pub(crate) struct ExternMain {
     #[primary_span]
diff --git a/compiler/rustc_privacy/messages.ftl b/compiler/rustc_privacy/messages.ftl
index 7785f1a7f81..43c34a109d7 100644
--- a/compiler/rustc_privacy/messages.ftl
+++ b/compiler/rustc_privacy/messages.ftl
@@ -1,5 +1,19 @@
-privacy_field_is_private = field `{$field_name}` of {$variant_descr} `{$def_path_str}` is private
-privacy_field_is_private_is_update_syntax_label = field `{$field_name}` is private
+privacy_field_is_private =
+    {$len ->
+        [1] field
+        *[other] fields
+    } {$field_names} of {$variant_descr} `{$def_path_str}` {$len ->
+        [1] is
+        *[other] are
+    } private
+    .label = in this type
+privacy_field_is_private_is_update_syntax_label = {$rest_len ->
+        [1] field
+        *[other] fields
+    } {$rest_field_names} {$rest_len ->
+        [1] is
+        *[other] are
+    } private
 privacy_field_is_private_label = private field
 
 privacy_from_private_dep_in_public_interface =
diff --git a/compiler/rustc_privacy/src/errors.rs b/compiler/rustc_privacy/src/errors.rs
index f5e641eb642..4d1d58c0852 100644
--- a/compiler/rustc_privacy/src/errors.rs
+++ b/compiler/rustc_privacy/src/errors.rs
@@ -1,5 +1,5 @@
-use rustc_errors::DiagArgFromDisplay;
 use rustc_errors::codes::*;
+use rustc_errors::{DiagArgFromDisplay, MultiSpan};
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_span::{Span, Symbol};
 
@@ -7,12 +7,15 @@ use rustc_span::{Span, Symbol};
 #[diag(privacy_field_is_private, code = E0451)]
 pub(crate) struct FieldIsPrivate {
     #[primary_span]
-    pub span: Span,
-    pub field_name: Symbol,
+    pub span: MultiSpan,
+    #[label]
+    pub struct_span: Option<Span>,
+    pub field_names: String,
     pub variant_descr: &'static str,
     pub def_path_str: String,
     #[subdiagnostic]
-    pub label: FieldIsPrivateLabel,
+    pub labels: Vec<FieldIsPrivateLabel>,
+    pub len: usize,
 }
 
 #[derive(Subdiagnostic)]
@@ -21,7 +24,8 @@ pub(crate) enum FieldIsPrivateLabel {
     IsUpdateSyntax {
         #[primary_span]
         span: Span,
-        field_name: Symbol,
+        rest_field_names: String,
+        rest_len: usize,
     },
     #[label(privacy_field_is_private_label)]
     Other {
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index e484cfed06b..cb7b0815a49 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -24,6 +24,7 @@ use rustc_ast::MacroDef;
 use rustc_ast::visit::{VisitorResult, try_visit};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::intern::Interned;
+use rustc_errors::MultiSpan;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId, LocalModDefId};
 use rustc_hir::intravisit::{self, Visitor};
@@ -38,7 +39,7 @@ use rustc_middle::ty::{
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
 use rustc_span::hygiene::Transparency;
-use rustc_span::{Ident, Span, kw, sym};
+use rustc_span::{Ident, Span, Symbol, kw, sym};
 use tracing::debug;
 use {rustc_attr_parsing as attr, rustc_hir as hir};
 
@@ -921,31 +922,95 @@ impl<'tcx> NamePrivacyVisitor<'tcx> {
         &mut self,
         hir_id: hir::HirId,    // ID of the field use
         use_ctxt: Span,        // syntax context of the field name at the use site
-        span: Span,            // span of the field pattern, e.g., `x: 0`
         def: ty::AdtDef<'tcx>, // definition of the struct or enum
         field: &'tcx ty::FieldDef,
-        in_update_syntax: bool,
-    ) {
+    ) -> bool {
         if def.is_enum() {
-            return;
+            return true;
         }
 
         // definition of the field
         let ident = Ident::new(kw::Empty, use_ctxt);
         let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id).1;
-        if !field.vis.is_accessible_from(def_id, self.tcx) {
-            self.tcx.dcx().emit_err(FieldIsPrivate {
-                span,
-                field_name: field.name,
-                variant_descr: def.variant_descr(),
-                def_path_str: self.tcx.def_path_str(def.did()),
-                label: if in_update_syntax {
-                    FieldIsPrivateLabel::IsUpdateSyntax { span, field_name: field.name }
-                } else {
-                    FieldIsPrivateLabel::Other { span }
-                },
-            });
+        !field.vis.is_accessible_from(def_id, self.tcx)
+    }
+
+    // Checks that a field in a struct constructor (expression or pattern) is accessible.
+    fn emit_unreachable_field_error(
+        &mut self,
+        fields: Vec<(Symbol, Span, bool /* field is present */)>,
+        def: ty::AdtDef<'tcx>, // definition of the struct or enum
+        update_syntax: Option<Span>,
+        struct_span: Span,
+    ) {
+        if def.is_enum() || fields.is_empty() {
+            return;
         }
+
+        //   error[E0451]: fields `beta` and `gamma` of struct `Alpha` are private
+        //   --> $DIR/visibility.rs:18:13
+        //    |
+        // LL |     let _x = Alpha {
+        //    |              ----- in this type      # from `def`
+        // LL |         beta: 0,
+        //    |         ^^^^^^^ private field        # `fields.2` is `true`
+        // LL |         ..
+        //    |         ^^ field `gamma` is private  # `fields.2` is `false`
+
+        // Get the list of all private fields for the main message.
+        let field_names: Vec<_> = fields.iter().map(|(name, _, _)| name).collect();
+        let field_names = match &field_names[..] {
+            [] => return,
+            [name] => format!("`{name}`"),
+            [fields @ .., last] => format!(
+                "{} and `{last}`",
+                fields.iter().map(|f| format!("`{f}`")).collect::<Vec<_>>().join(", "),
+            ),
+        };
+        let span: MultiSpan = fields.iter().map(|(_, span, _)| *span).collect::<Vec<Span>>().into();
+
+        // Get the list of all private fields when pointing at the `..rest`.
+        let rest_field_names: Vec<_> =
+            fields.iter().filter(|(_, _, is_present)| !is_present).map(|(n, _, _)| n).collect();
+        let rest_len = rest_field_names.len();
+        let rest_field_names = match &rest_field_names[..] {
+            [] => String::new(),
+            [name] => format!("`{name}`"),
+            [fields @ .., last] => format!(
+                "{} and `{last}`",
+                fields.iter().map(|f| format!("`{f}`")).collect::<Vec<_>>().join(", "),
+            ),
+        };
+        // Get all the labels for each field or `..rest` in the primary MultiSpan.
+        let labels = fields
+            .iter()
+            .filter(|(_, _, is_present)| *is_present)
+            .map(|(_, span, _)| FieldIsPrivateLabel::Other { span: *span })
+            .chain(update_syntax.iter().map(|span| FieldIsPrivateLabel::IsUpdateSyntax {
+                span: *span,
+                rest_field_names: rest_field_names.clone(),
+                rest_len,
+            }))
+            .collect();
+
+        self.tcx.dcx().emit_err(FieldIsPrivate {
+            span,
+            struct_span: if self
+                .tcx
+                .sess
+                .source_map()
+                .is_multiline(fields[0].1.between(struct_span))
+            {
+                Some(struct_span)
+            } else {
+                None
+            },
+            field_names: field_names.clone(),
+            variant_descr: def.variant_descr(),
+            def_path_str: self.tcx.def_path_str(def.did()),
+            labels,
+            len: fields.len(),
+        });
     }
 
     fn check_expanded_fields(
@@ -955,7 +1020,9 @@ impl<'tcx> NamePrivacyVisitor<'tcx> {
         fields: &[hir::ExprField<'tcx>],
         hir_id: hir::HirId,
         span: Span,
+        struct_span: Span,
     ) {
+        let mut failed_fields = vec![];
         for (vf_index, variant_field) in variant.fields.iter_enumerated() {
             let field =
                 fields.iter().find(|f| self.typeck_results().field_index(f.hir_id) == vf_index);
@@ -963,8 +1030,15 @@ impl<'tcx> NamePrivacyVisitor<'tcx> {
                 Some(field) => (field.hir_id, field.ident.span, field.span),
                 None => (hir_id, span, span),
             };
-            self.check_field(hir_id, use_ctxt, span, adt, variant_field, true);
+            if self.check_field(hir_id, use_ctxt, adt, variant_field) {
+                let name = match field {
+                    Some(field) => field.ident.name,
+                    None => variant_field.name,
+                };
+                failed_fields.push((name, span, field.is_some()));
+            }
         }
+        self.emit_unreachable_field_error(failed_fields, adt, Some(span), struct_span);
     }
 }
 
@@ -990,24 +1064,35 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
                     // If the expression uses FRU we need to make sure all the unmentioned fields
                     // are checked for privacy (RFC 736). Rather than computing the set of
                     // unmentioned fields, just check them all.
-                    self.check_expanded_fields(adt, variant, fields, base.hir_id, base.span);
+                    self.check_expanded_fields(
+                        adt,
+                        variant,
+                        fields,
+                        base.hir_id,
+                        base.span,
+                        qpath.span(),
+                    );
                 }
                 hir::StructTailExpr::DefaultFields(span) => {
-                    self.check_expanded_fields(adt, variant, fields, expr.hir_id, span);
+                    self.check_expanded_fields(
+                        adt,
+                        variant,
+                        fields,
+                        expr.hir_id,
+                        span,
+                        qpath.span(),
+                    );
                 }
                 hir::StructTailExpr::None => {
+                    let mut failed_fields = vec![];
                     for field in fields {
-                        let (hir_id, use_ctxt, span) = (field.hir_id, field.ident.span, field.span);
+                        let (hir_id, use_ctxt) = (field.hir_id, field.ident.span);
                         let index = self.typeck_results().field_index(field.hir_id);
-                        self.check_field(
-                            hir_id,
-                            use_ctxt,
-                            span,
-                            adt,
-                            &variant.fields[index],
-                            false,
-                        );
+                        if self.check_field(hir_id, use_ctxt, adt, &variant.fields[index]) {
+                            failed_fields.push((field.ident.name, field.ident.span, true));
+                        }
                     }
+                    self.emit_unreachable_field_error(failed_fields, adt, None, qpath.span());
                 }
             }
         }
@@ -1020,11 +1105,15 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
             let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
             let adt = self.typeck_results().pat_ty(pat).ty_adt_def().unwrap();
             let variant = adt.variant_of_res(res);
+            let mut failed_fields = vec![];
             for field in fields {
-                let (hir_id, use_ctxt, span) = (field.hir_id, field.ident.span, field.span);
+                let (hir_id, use_ctxt) = (field.hir_id, field.ident.span);
                 let index = self.typeck_results().field_index(field.hir_id);
-                self.check_field(hir_id, use_ctxt, span, adt, &variant.fields[index], false);
+                if self.check_field(hir_id, use_ctxt, adt, &variant.fields[index]) {
+                    failed_fields.push((field.ident.name, field.ident.span, true));
+                }
             }
+            self.emit_unreachable_field_error(failed_fields, adt, None, qpath.span());
         }
 
         intravisit::walk_pat(self, pat);
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index 3e179c61f39..a8c2aa98cd0 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -567,7 +567,7 @@ pub fn print_query_stack<Qcx: QueryContext>(
     qcx: Qcx,
     mut current_query: Option<QueryJobId>,
     dcx: DiagCtxtHandle<'_>,
-    num_frames: Option<usize>,
+    limit_frames: Option<usize>,
     mut file: Option<std::fs::File>,
 ) -> usize {
     // Be careful relying on global state here: this code is called from
@@ -584,7 +584,7 @@ pub fn print_query_stack<Qcx: QueryContext>(
         let Some(query_info) = query_map.get(&query) else {
             break;
         };
-        if Some(count_printed) < num_frames || num_frames.is_none() {
+        if Some(count_printed) < limit_frames || limit_frames.is_none() {
             // Only print to stderr as many stack frames as `num_frames` when present.
             // FIXME: needs translation
             #[allow(rustc::diagnostic_outside_of_impl)]
@@ -615,5 +615,5 @@ pub fn print_query_stack<Qcx: QueryContext>(
     if let Some(ref mut file) = file {
         let _ = writeln!(file, "end of query stack");
     }
-    count_printed
+    count_total
 }
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 3fe1eed243f..eec9e9a8515 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -645,10 +645,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                 let self_spans = items
                     .iter()
                     .filter_map(|(use_tree, _)| {
-                        if let ast::UseTreeKind::Simple(..) = use_tree.kind {
-                            if use_tree.ident().name == kw::SelfLower {
-                                return Some(use_tree.span);
-                            }
+                        if let ast::UseTreeKind::Simple(..) = use_tree.kind
+                            && use_tree.ident().name == kw::SelfLower
+                        {
+                            return Some(use_tree.span);
                         }
 
                         None
@@ -947,19 +947,19 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
         let imported_binding = self.r.import(binding, import);
         if parent == self.r.graph_root {
             let ident = ident.normalize_to_macros_2_0();
-            if let Some(entry) = self.r.extern_prelude.get(&ident) {
-                if expansion != LocalExpnId::ROOT && orig_name.is_some() && !entry.is_import() {
-                    self.r.dcx().emit_err(
-                        errors::MacroExpandedExternCrateCannotShadowExternArguments {
-                            span: item.span,
-                        },
-                    );
-                    // `return` is intended to discard this binding because it's an
-                    // unregistered ambiguity error which would result in a panic
-                    // caused by inconsistency `path_res`
-                    // more details: https://github.com/rust-lang/rust/pull/111761
-                    return;
-                }
+            if let Some(entry) = self.r.extern_prelude.get(&ident)
+                && expansion != LocalExpnId::ROOT
+                && orig_name.is_some()
+                && !entry.is_import()
+            {
+                self.r.dcx().emit_err(
+                    errors::MacroExpandedExternCrateCannotShadowExternArguments { span: item.span },
+                );
+                // `return` is intended to discard this binding because it's an
+                // unregistered ambiguity error which would result in a panic
+                // caused by inconsistency `path_res`
+                // more details: https://github.com/rust-lang/rust/pull/111761
+                return;
             }
             let entry = self
                 .r
@@ -1040,10 +1040,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                         span: item.span,
                     });
                 }
-                if let ItemKind::ExternCrate(Some(orig_name)) = item.kind {
-                    if orig_name == kw::SelfLower {
-                        self.r.dcx().emit_err(errors::MacroUseExternCrateSelf { span: attr.span });
-                    }
+                if let ItemKind::ExternCrate(Some(orig_name)) = item.kind
+                    && orig_name == kw::SelfLower
+                {
+                    self.r.dcx().emit_err(errors::MacroUseExternCrateSelf { span: attr.span });
                 }
                 let ill_formed = |span| {
                     self.r.dcx().emit_err(errors::BadMacroImport { span });
@@ -1179,14 +1179,12 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
             return Some((MacroKind::Bang, item.ident, item.span));
         } else if ast::attr::contains_name(&item.attrs, sym::proc_macro_attribute) {
             return Some((MacroKind::Attr, item.ident, item.span));
-        } else if let Some(attr) = ast::attr::find_by_name(&item.attrs, sym::proc_macro_derive) {
-            if let Some(meta_item_inner) =
+        } else if let Some(attr) = ast::attr::find_by_name(&item.attrs, sym::proc_macro_derive)
+            && let Some(meta_item_inner) =
                 attr.meta_item_list().and_then(|list| list.get(0).cloned())
-            {
-                if let Some(ident) = meta_item_inner.ident() {
-                    return Some((MacroKind::Derive, ident, ident.span));
-                }
-            }
+            && let Some(ident) = meta_item_inner.ident()
+        {
+            return Some((MacroKind::Derive, ident, ident.span));
         }
         None
     }
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 5a605df88c2..1c1e8494ffc 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -397,7 +397,7 @@ impl Resolver<'_, '_> {
                 }
                 ImportKind::ExternCrate { id, .. } => {
                     let def_id = self.local_def_id(id);
-                    if self.extern_crate_map.get(&def_id).map_or(true, |&cnum| {
+                    if self.extern_crate_map.get(&def_id).is_none_or(|&cnum| {
                         !tcx.is_compiler_builtins(cnum)
                             && !tcx.is_panic_runtime(cnum)
                             && !tcx.has_global_allocator(cnum)
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index dc26d4de57a..43e4e4d591f 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -30,7 +30,7 @@ use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::SourceMap;
 use rustc_span::{BytePos, Ident, Span, Symbol, SyntaxContext, kw, sym};
 use thin_vec::{ThinVec, thin_vec};
-use tracing::debug;
+use tracing::{debug, instrument};
 
 use crate::errors::{
     self, AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive,
@@ -225,10 +225,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         let (name, span) =
             (ident.name, self.tcx.sess.source_map().guess_head_span(new_binding.span));
 
-        if let Some(s) = self.name_already_seen.get(&name) {
-            if s == &span {
-                return;
-            }
+        if self.name_already_seen.get(&name) == Some(&span) {
+            return;
         }
 
         let old_kind = match (ns, old_binding.module()) {
@@ -322,7 +320,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         let duplicate = new_binding.res().opt_def_id() == old_binding.res().opt_def_id();
         let has_dummy_span = new_binding.span.is_dummy() || old_binding.span.is_dummy();
         let from_item =
-            self.extern_prelude.get(&ident).map_or(true, |entry| entry.introduced_by_item);
+            self.extern_prelude.get(&ident).is_none_or(|entry| entry.introduced_by_item);
         // Only suggest removing an import if both bindings are to the same def, if both spans
         // aren't dummy spans. Further, if both bindings are imports, then the ident must have
         // been introduced by an item.
@@ -380,20 +378,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 suggestion = Some(format!("self as {suggested_name}"))
             }
             ImportKind::Single { source, .. } => {
-                if let Some(pos) =
-                    source.span.hi().0.checked_sub(binding_span.lo().0).map(|pos| pos as usize)
+                if let Some(pos) = source.span.hi().0.checked_sub(binding_span.lo().0)
+                    && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(binding_span)
+                    && pos as usize <= snippet.len()
                 {
-                    if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(binding_span) {
-                        if pos <= snippet.len() {
-                            span = binding_span
-                                .with_lo(binding_span.lo() + BytePos(pos as u32))
-                                .with_hi(
-                                    binding_span.hi()
-                                        - BytePos(if snippet.ends_with(';') { 1 } else { 0 }),
-                                );
-                            suggestion = Some(format!(" as {suggested_name}"));
-                        }
-                    }
+                    span = binding_span.with_lo(binding_span.lo() + BytePos(pos)).with_hi(
+                        binding_span.hi() - BytePos(if snippet.ends_with(';') { 1 } else { 0 }),
+                    );
+                    suggestion = Some(format!(" as {suggested_name}"));
                 }
             }
             ImportKind::ExternCrate { source, target, .. } => {
@@ -510,13 +502,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         // If the first element of our path was actually resolved to an
         // `ExternCrate` (also used for `crate::...`) then no need to issue a
         // warning, this looks all good!
-        if let Some(binding) = second_binding {
-            if let NameBindingKind::Import { import, .. } = binding.kind {
-                // Careful: we still want to rewrite paths from renamed extern crates.
-                if let ImportKind::ExternCrate { source: None, .. } = import.kind {
-                    return;
-                }
-            }
+        if let Some(binding) = second_binding
+            && let NameBindingKind::Import { import, .. } = binding.kind
+            // Careful: we still want to rewrite paths from renamed extern crates.
+            && let ImportKind::ExternCrate { source: None, .. } = import.kind
+        {
+            return;
         }
 
         let diag = BuiltinLintDiag::AbsPathWithModule(root_span);
@@ -537,7 +528,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     ) {
         module.for_each_child(self, |_this, ident, _ns, binding| {
             let res = binding.res();
-            if filter_fn(res) && ctxt.map_or(true, |ctxt| ctxt == ident.span.ctxt()) {
+            if filter_fn(res) && ctxt.is_none_or(|ctxt| ctxt == ident.span.ctxt()) {
                 names.push(TypoSuggestion::typo_from_ident(ident, res));
             }
         });
@@ -1047,20 +1038,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     if filter_fn(res) {
                         for derive in parent_scope.derives {
                             let parent_scope = &ParentScope { derives: &[], ..*parent_scope };
-                            if let Ok((Some(ext), _)) = this.resolve_macro_path(
+                            let Ok((Some(ext), _)) = this.resolve_macro_path(
                                 derive,
                                 Some(MacroKind::Derive),
                                 parent_scope,
                                 false,
                                 false,
                                 None,
-                            ) {
-                                suggestions.extend(
-                                    ext.helper_attrs
-                                        .iter()
-                                        .map(|name| TypoSuggestion::typo_from_name(*name, res)),
-                                );
-                            }
+                            ) else {
+                                continue;
+                            };
+                            suggestions.extend(
+                                ext.helper_attrs
+                                    .iter()
+                                    .map(|name| TypoSuggestion::typo_from_name(*name, res)),
+                            );
                         }
                     }
                 }
@@ -1215,12 +1207,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 }
 
                 // #90113: Do not count an inaccessible reexported item as a candidate.
-                if let NameBindingKind::Import { binding, .. } = name_binding.kind {
-                    if this.is_accessible_from(binding.vis, parent_scope.module)
-                        && !this.is_accessible_from(name_binding.vis, parent_scope.module)
-                    {
-                        return;
-                    }
+                if let NameBindingKind::Import { binding, .. } = name_binding.kind
+                    && this.is_accessible_from(binding.vis, parent_scope.module)
+                    && !this.is_accessible_from(name_binding.vis, parent_scope.module)
+                {
+                    return;
                 }
 
                 let res = name_binding.res();
@@ -1229,7 +1220,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     _ => res.opt_def_id(),
                 };
                 let child_doc_visible = doc_visible
-                    && (did.map_or(true, |did| did.is_local() || !this.tcx.is_doc_hidden(did)));
+                    && did.is_none_or(|did| did.is_local() || !this.tcx.is_doc_hidden(did));
 
                 // collect results based on the filter function
                 // avoid suggesting anything from the same module in which we are resolving
@@ -1253,14 +1244,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     segms.push(ast::PathSegment::from_ident(ident));
                     let path = Path { span: name_binding.span, segments: segms, tokens: None };
 
-                    if child_accessible {
+                    if child_accessible
                         // Remove invisible match if exists
-                        if let Some(idx) = candidates
+                        && let Some(idx) = candidates
                             .iter()
                             .position(|v: &ImportSuggestion| v.did == did && !v.accessible)
-                        {
-                            candidates.remove(idx);
-                        }
+                    {
+                        candidates.remove(idx);
                     }
 
                     if candidates.iter().all(|v: &ImportSuggestion| v.did != did) {
@@ -1373,48 +1363,50 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     // otherwise cause duplicate suggestions.
                     continue;
                 }
-                let crate_id = self.crate_loader(|c| c.maybe_process_path_extern(ident.name));
-                if let Some(crate_id) = crate_id {
-                    let crate_def_id = crate_id.as_def_id();
-                    let crate_root = self.expect_module(crate_def_id);
-
-                    // Check if there's already an item in scope with the same name as the crate.
-                    // If so, we have to disambiguate the potential import suggestions by making
-                    // the paths *global* (i.e., by prefixing them with `::`).
-                    let needs_disambiguation =
-                        self.resolutions(parent_scope.module).borrow().iter().any(
-                            |(key, name_resolution)| {
-                                if key.ns == TypeNS
-                                    && key.ident == ident
-                                    && let Some(binding) = name_resolution.borrow().binding
-                                {
-                                    match binding.res() {
-                                        // No disambiguation needed if the identically named item we
-                                        // found in scope actually refers to the crate in question.
-                                        Res::Def(_, def_id) => def_id != crate_def_id,
-                                        Res::PrimTy(_) => true,
-                                        _ => false,
-                                    }
-                                } else {
-                                    false
-                                }
-                            },
-                        );
-                    let mut crate_path = ThinVec::new();
-                    if needs_disambiguation {
-                        crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP));
-                    }
-                    crate_path.push(ast::PathSegment::from_ident(ident));
+                let Some(crate_id) = self.crate_loader(|c| c.maybe_process_path_extern(ident.name))
+                else {
+                    continue;
+                };
 
-                    suggestions.extend(self.lookup_import_candidates_from_module(
-                        lookup_ident,
-                        namespace,
-                        parent_scope,
-                        crate_root,
-                        crate_path,
-                        &filter_fn,
-                    ));
+                let crate_def_id = crate_id.as_def_id();
+                let crate_root = self.expect_module(crate_def_id);
+
+                // Check if there's already an item in scope with the same name as the crate.
+                // If so, we have to disambiguate the potential import suggestions by making
+                // the paths *global* (i.e., by prefixing them with `::`).
+                let needs_disambiguation =
+                    self.resolutions(parent_scope.module).borrow().iter().any(
+                        |(key, name_resolution)| {
+                            if key.ns == TypeNS
+                                && key.ident == ident
+                                && let Some(binding) = name_resolution.borrow().binding
+                            {
+                                match binding.res() {
+                                    // No disambiguation needed if the identically named item we
+                                    // found in scope actually refers to the crate in question.
+                                    Res::Def(_, def_id) => def_id != crate_def_id,
+                                    Res::PrimTy(_) => true,
+                                    _ => false,
+                                }
+                            } else {
+                                false
+                            }
+                        },
+                    );
+                let mut crate_path = ThinVec::new();
+                if needs_disambiguation {
+                    crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP));
                 }
+                crate_path.push(ast::PathSegment::from_ident(ident));
+
+                suggestions.extend(self.lookup_import_candidates_from_module(
+                    lookup_ident,
+                    namespace,
+                    parent_scope,
+                    crate_root,
+                    crate_path,
+                    &filter_fn,
+                ));
             }
         }
 
@@ -1511,7 +1503,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             });
         }
         for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] {
-            if let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
+            let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
                 ident,
                 ScopeSet::All(ns),
                 parent_scope,
@@ -1519,53 +1511,53 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 false,
                 None,
                 None,
-            ) {
-                let desc = match binding.res() {
-                    Res::Def(DefKind::Macro(MacroKind::Bang), _) => {
-                        "a function-like macro".to_string()
-                    }
-                    Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => {
-                        format!("an attribute: `#[{ident}]`")
-                    }
-                    Res::Def(DefKind::Macro(MacroKind::Derive), _) => {
-                        format!("a derive macro: `#[derive({ident})]`")
-                    }
-                    Res::ToolMod => {
-                        // Don't confuse the user with tool modules.
-                        continue;
-                    }
-                    Res::Def(DefKind::Trait, _) if macro_kind == MacroKind::Derive => {
-                        "only a trait, without a derive macro".to_string()
-                    }
-                    res => format!(
-                        "{} {}, not {} {}",
-                        res.article(),
-                        res.descr(),
-                        macro_kind.article(),
-                        macro_kind.descr_expected(),
-                    ),
-                };
-                if let crate::NameBindingKind::Import { import, .. } = binding.kind {
-                    if !import.span.is_dummy() {
-                        let note = errors::IdentImporterHereButItIsDesc {
-                            span: import.span,
-                            imported_ident: ident,
-                            imported_ident_desc: &desc,
-                        };
-                        err.subdiagnostic(note);
-                        // Silence the 'unused import' warning we might get,
-                        // since this diagnostic already covers that import.
-                        self.record_use(ident, binding, Used::Other);
-                        return;
-                    }
+            ) else {
+                continue;
+            };
+
+            let desc = match binding.res() {
+                Res::Def(DefKind::Macro(MacroKind::Bang), _) => "a function-like macro".to_string(),
+                Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => {
+                    format!("an attribute: `#[{ident}]`")
                 }
-                let note = errors::IdentInScopeButItIsDesc {
+                Res::Def(DefKind::Macro(MacroKind::Derive), _) => {
+                    format!("a derive macro: `#[derive({ident})]`")
+                }
+                Res::ToolMod => {
+                    // Don't confuse the user with tool modules.
+                    continue;
+                }
+                Res::Def(DefKind::Trait, _) if macro_kind == MacroKind::Derive => {
+                    "only a trait, without a derive macro".to_string()
+                }
+                res => format!(
+                    "{} {}, not {} {}",
+                    res.article(),
+                    res.descr(),
+                    macro_kind.article(),
+                    macro_kind.descr_expected(),
+                ),
+            };
+            if let crate::NameBindingKind::Import { import, .. } = binding.kind
+                && !import.span.is_dummy()
+            {
+                let note = errors::IdentImporterHereButItIsDesc {
+                    span: import.span,
                     imported_ident: ident,
                     imported_ident_desc: &desc,
                 };
                 err.subdiagnostic(note);
+                // Silence the 'unused import' warning we might get,
+                // since this diagnostic already covers that import.
+                self.record_use(ident, binding, Used::Other);
                 return;
             }
+            let note = errors::IdentInScopeButItIsDesc {
+                imported_ident: ident,
+                imported_ident_desc: &desc,
+            };
+            err.subdiagnostic(note);
+            return;
         }
     }
 
@@ -1749,15 +1741,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     /// If the binding refers to a tuple struct constructor with fields,
     /// returns the span of its fields.
     fn ctor_fields_span(&self, binding: NameBinding<'_>) -> Option<Span> {
-        if let NameBindingKind::Res(Res::Def(
+        let NameBindingKind::Res(Res::Def(
             DefKind::Ctor(CtorOf::Struct, CtorKind::Fn),
             ctor_def_id,
         )) = binding.kind
-        {
-            let def_id = self.tcx.parent(ctor_def_id);
-            return self.field_idents(def_id)?.iter().map(|&f| f.span).reduce(Span::to); // None for `struct Foo()`
-        }
-        None
+        else {
+            return None;
+        };
+
+        let def_id = self.tcx.parent(ctor_def_id);
+        self.field_idents(def_id)?.iter().map(|&f| f.span).reduce(Span::to) // None for `struct Foo()`
     }
 
     fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) {
@@ -1983,10 +1976,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             .collect::<Vec<_>>();
         candidates.sort();
         candidates.dedup();
-        match find_best_match_for_name(&candidates, ident, None) {
-            Some(sugg) if sugg == ident => None,
-            sugg => sugg,
-        }
+        find_best_match_for_name(&candidates, ident, None).filter(|sugg| *sugg != ident)
     }
 
     pub(crate) fn report_path_resolution_error(
@@ -2235,14 +2225,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     }
 
     /// Adds suggestions for a path that cannot be resolved.
+    #[instrument(level = "debug", skip(self, parent_scope))]
     pub(crate) fn make_path_suggestion(
         &mut self,
         span: Span,
         mut path: Vec<Segment>,
         parent_scope: &ParentScope<'ra>,
     ) -> Option<(Vec<Segment>, Option<String>)> {
-        debug!("make_path_suggestion: span={:?} path={:?}", span, path);
-
         match (path.get(0), path.get(1)) {
             // `{{root}}::ident::...` on both editions.
             // On 2015 `{{root}}` is usually added implicitly.
@@ -2271,6 +2260,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     /// LL | use foo::Bar;
     ///    |     ^^^ did you mean `self::foo`?
     /// ```
+    #[instrument(level = "debug", skip(self, parent_scope))]
     fn make_missing_self_suggestion(
         &mut self,
         mut path: Vec<Segment>,
@@ -2279,7 +2269,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         // Replace first ident with `self` and check if that is valid.
         path[0].ident.name = kw::SelfLower;
         let result = self.maybe_resolve_path(&path, None, parent_scope, None);
-        debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result);
+        debug!(?path, ?result);
         if let PathResult::Module(..) = result { Some((path, None)) } else { None }
     }
 
@@ -2290,6 +2280,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     /// LL | use foo::Bar;
     ///    |     ^^^ did you mean `crate::foo`?
     /// ```
+    #[instrument(level = "debug", skip(self, parent_scope))]
     fn make_missing_crate_suggestion(
         &mut self,
         mut path: Vec<Segment>,
@@ -2298,7 +2289,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         // Replace first ident with `crate` and check if that is valid.
         path[0].ident.name = kw::Crate;
         let result = self.maybe_resolve_path(&path, None, parent_scope, None);
-        debug!("make_missing_crate_suggestion:  path={:?} result={:?}", path, result);
+        debug!(?path, ?result);
         if let PathResult::Module(..) = result {
             Some((
                 path,
@@ -2321,6 +2312,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     /// LL | use foo::Bar;
     ///    |     ^^^ did you mean `super::foo`?
     /// ```
+    #[instrument(level = "debug", skip(self, parent_scope))]
     fn make_missing_super_suggestion(
         &mut self,
         mut path: Vec<Segment>,
@@ -2329,7 +2321,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         // Replace first ident with `crate` and check if that is valid.
         path[0].ident.name = kw::Super;
         let result = self.maybe_resolve_path(&path, None, parent_scope, None);
-        debug!("make_missing_super_suggestion:  path={:?} result={:?}", path, result);
+        debug!(?path, ?result);
         if let PathResult::Module(..) = result { Some((path, None)) } else { None }
     }
 
@@ -2343,6 +2335,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     ///
     /// Used when importing a submodule of an external crate but missing that crate's
     /// name as the first part of path.
+    #[instrument(level = "debug", skip(self, parent_scope))]
     fn make_external_crate_suggestion(
         &mut self,
         mut path: Vec<Segment>,
@@ -2363,10 +2356,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             // Replace first ident with a crate name and check if that is valid.
             path[0].ident.name = name;
             let result = self.maybe_resolve_path(&path, None, parent_scope, None);
-            debug!(
-                "make_external_crate_suggestion: name={:?} path={:?} result={:?}",
-                name, path, result
-            );
+            debug!(?path, ?name, ?result);
             if let PathResult::Module(..) = result {
                 return Some((path, None));
             }
@@ -2410,121 +2400,115 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         let binding_key = BindingKey::new(ident, MacroNS);
         let resolution = resolutions.get(&binding_key)?;
         let binding = resolution.borrow().binding()?;
-        if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() {
-            let module_name = crate_module.kind.name().unwrap();
-            let import_snippet = match import.kind {
-                ImportKind::Single { source, target, .. } if source != target => {
-                    format!("{source} as {target}")
-                }
-                _ => format!("{ident}"),
-            };
+        let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() else {
+            return None;
+        };
+        let module_name = crate_module.kind.name().unwrap();
+        let import_snippet = match import.kind {
+            ImportKind::Single { source, target, .. } if source != target => {
+                format!("{source} as {target}")
+            }
+            _ => format!("{ident}"),
+        };
 
-            let mut corrections: Vec<(Span, String)> = Vec::new();
-            if !import.is_nested() {
-                // Assume this is the easy case of `use issue_59764::foo::makro;` and just remove
-                // intermediate segments.
-                corrections.push((import.span, format!("{module_name}::{import_snippet}")));
-            } else {
-                // Find the binding span (and any trailing commas and spaces).
-                //   ie. `use a::b::{c, d, e};`
-                //                      ^^^
-                let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding(
-                    self.tcx.sess,
-                    import.span,
-                    import.use_span,
-                );
-                debug!(
-                    "check_for_module_export_macro: found_closing_brace={:?} binding_span={:?}",
-                    found_closing_brace, binding_span
-                );
+        let mut corrections: Vec<(Span, String)> = Vec::new();
+        if !import.is_nested() {
+            // Assume this is the easy case of `use issue_59764::foo::makro;` and just remove
+            // intermediate segments.
+            corrections.push((import.span, format!("{module_name}::{import_snippet}")));
+        } else {
+            // Find the binding span (and any trailing commas and spaces).
+            //   ie. `use a::b::{c, d, e};`
+            //                      ^^^
+            let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding(
+                self.tcx.sess,
+                import.span,
+                import.use_span,
+            );
+            debug!(found_closing_brace, ?binding_span);
+
+            let mut removal_span = binding_span;
+
+            // If the binding span ended with a closing brace, as in the below example:
+            //   ie. `use a::b::{c, d};`
+            //                      ^
+            // Then expand the span of characters to remove to include the previous
+            // binding's trailing comma.
+            //   ie. `use a::b::{c, d};`
+            //                    ^^^
+            if found_closing_brace
+                && let Some(previous_span) =
+                    extend_span_to_previous_binding(self.tcx.sess, binding_span)
+            {
+                debug!(?previous_span);
+                removal_span = removal_span.with_lo(previous_span.lo());
+            }
+            debug!(?removal_span);
 
-                let mut removal_span = binding_span;
-                if found_closing_brace {
-                    // If the binding span ended with a closing brace, as in the below example:
-                    //   ie. `use a::b::{c, d};`
-                    //                      ^
-                    // Then expand the span of characters to remove to include the previous
-                    // binding's trailing comma.
-                    //   ie. `use a::b::{c, d};`
-                    //                    ^^^
-                    if let Some(previous_span) =
-                        extend_span_to_previous_binding(self.tcx.sess, binding_span)
-                    {
-                        debug!("check_for_module_export_macro: previous_span={:?}", previous_span);
-                        removal_span = removal_span.with_lo(previous_span.lo());
-                    }
-                }
-                debug!("check_for_module_export_macro: removal_span={:?}", removal_span);
-
-                // Remove the `removal_span`.
-                corrections.push((removal_span, "".to_string()));
-
-                // Find the span after the crate name and if it has nested imports immediately
-                // after the crate name already.
-                //   ie. `use a::b::{c, d};`
-                //               ^^^^^^^^^
-                //   or  `use a::{b, c, d}};`
-                //               ^^^^^^^^^^^
-                let (has_nested, after_crate_name) = find_span_immediately_after_crate_name(
-                    self.tcx.sess,
-                    module_name,
-                    import.use_span,
-                );
-                debug!(
-                    "check_for_module_export_macro: has_nested={:?} after_crate_name={:?}",
-                    has_nested, after_crate_name
-                );
+            // Remove the `removal_span`.
+            corrections.push((removal_span, "".to_string()));
 
-                let source_map = self.tcx.sess.source_map();
+            // Find the span after the crate name and if it has nested imports immediately
+            // after the crate name already.
+            //   ie. `use a::b::{c, d};`
+            //               ^^^^^^^^^
+            //   or  `use a::{b, c, d}};`
+            //               ^^^^^^^^^^^
+            let (has_nested, after_crate_name) =
+                find_span_immediately_after_crate_name(self.tcx.sess, module_name, import.use_span);
+            debug!(has_nested, ?after_crate_name);
 
-                // Make sure this is actually crate-relative.
-                let is_definitely_crate = import
-                    .module_path
-                    .first()
-                    .is_some_and(|f| f.ident.name != kw::SelfLower && f.ident.name != kw::Super);
+            let source_map = self.tcx.sess.source_map();
 
-                // Add the import to the start, with a `{` if required.
-                let start_point = source_map.start_point(after_crate_name);
-                if is_definitely_crate
-                    && let Ok(start_snippet) = source_map.span_to_snippet(start_point)
-                {
-                    corrections.push((
-                        start_point,
-                        if has_nested {
-                            // In this case, `start_snippet` must equal '{'.
-                            format!("{start_snippet}{import_snippet}, ")
-                        } else {
-                            // In this case, add a `{`, then the moved import, then whatever
-                            // was there before.
-                            format!("{{{import_snippet}, {start_snippet}")
-                        },
-                    ));
+            // Make sure this is actually crate-relative.
+            let is_definitely_crate = import
+                .module_path
+                .first()
+                .is_some_and(|f| f.ident.name != kw::SelfLower && f.ident.name != kw::Super);
 
-                    // Add a `};` to the end if nested, matching the `{` added at the start.
-                    if !has_nested {
-                        corrections
-                            .push((source_map.end_point(after_crate_name), "};".to_string()));
-                    }
-                } else {
-                    // If the root import is module-relative, add the import separately
-                    corrections.push((
-                        import.use_span.shrink_to_lo(),
-                        format!("use {module_name}::{import_snippet};\n"),
-                    ));
+            // Add the import to the start, with a `{` if required.
+            let start_point = source_map.start_point(after_crate_name);
+            if is_definitely_crate
+                && let Ok(start_snippet) = source_map.span_to_snippet(start_point)
+            {
+                corrections.push((
+                    start_point,
+                    if has_nested {
+                        // In this case, `start_snippet` must equal '{'.
+                        format!("{start_snippet}{import_snippet}, ")
+                    } else {
+                        // In this case, add a `{`, then the moved import, then whatever
+                        // was there before.
+                        format!("{{{import_snippet}, {start_snippet}")
+                    },
+                ));
+
+                // Add a `};` to the end if nested, matching the `{` added at the start.
+                if !has_nested {
+                    corrections.push((source_map.end_point(after_crate_name), "};".to_string()));
                 }
+            } else {
+                // If the root import is module-relative, add the import separately
+                corrections.push((
+                    import.use_span.shrink_to_lo(),
+                    format!("use {module_name}::{import_snippet};\n"),
+                ));
             }
+        }
 
-            let suggestion = Some((
-                corrections,
-                String::from("a macro with this name exists at the root of the crate"),
-                Applicability::MaybeIncorrect,
-            ));
-            Some((suggestion, Some("this could be because a macro annotated with `#[macro_export]` will be exported \
+        let suggestion = Some((
+            corrections,
+            String::from("a macro with this name exists at the root of the crate"),
+            Applicability::MaybeIncorrect,
+        ));
+        Some((
+            suggestion,
+            Some(
+                "this could be because a macro annotated with `#[macro_export]` will be exported \
             at the root of the crate instead of the module where it is defined"
-               .to_string())))
-        } else {
-            None
-        }
+                    .to_string(),
+            ),
+        ))
     }
 
     /// Finds a cfg-ed out item inside `module` with the matching name.
@@ -2677,15 +2661,12 @@ fn extend_span_to_previous_binding(sess: &Session, binding_span: Span) -> Option
 /// use foo::{a, b::{c, d}};
 /// //       ^^^^^^^^^^^^^^^ -- true
 /// ```
+#[instrument(level = "debug", skip(sess))]
 fn find_span_immediately_after_crate_name(
     sess: &Session,
     module_name: Symbol,
     use_span: Span,
 ) -> (bool, Span) {
-    debug!(
-        "find_span_immediately_after_crate_name: module_name={:?} use_span={:?}",
-        module_name, use_span
-    );
     let source_map = sess.source_map();
 
     // Using `use issue_59764::foo::{baz, makro};` as an example throughout..
@@ -3051,7 +3032,6 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
                 self.first_legal_span = Some(inject);
             }
             self.first_use_span = search_for_any_use_in_items(&c.items);
-            return;
         } else {
             visit::walk_crate(self, c);
         }
@@ -3065,7 +3045,6 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
                     self.first_legal_span = Some(inject);
                 }
                 self.first_use_span = search_for_any_use_in_items(items);
-                return;
             }
         } else {
             visit::walk_item(self, item);
@@ -3075,16 +3054,16 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
 
 fn search_for_any_use_in_items(items: &[P<ast::Item>]) -> Option<Span> {
     for item in items {
-        if let ItemKind::Use(..) = item.kind {
-            if is_span_suitable_for_use_injection(item.span) {
-                let mut lo = item.span.lo();
-                for attr in &item.attrs {
-                    if attr.span.eq_ctxt(item.span) {
-                        lo = std::cmp::min(lo, attr.span.lo());
-                    }
+        if let ItemKind::Use(..) = item.kind
+            && is_span_suitable_for_use_injection(item.span)
+        {
+            let mut lo = item.span.lo();
+            for attr in &item.attrs {
+                if attr.span.eq_ctxt(item.span) {
+                    lo = std::cmp::min(lo, attr.span.lo());
                 }
-                return Some(Span::new(lo, lo, item.span.ctxt(), item.span.parent()));
             }
+            return Some(Span::new(lo, lo, item.span.ctxt(), item.span.parent()));
         }
     }
     None
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
index e279d14704e..6ef4aa40725 100644
--- a/compiler/rustc_resolve/src/effective_visibilities.rs
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -118,37 +118,38 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> {
         let resolutions = self.r.resolutions(module);
 
         for (_, name_resolution) in resolutions.borrow().iter() {
-            if let Some(mut binding) = name_resolution.borrow().binding() {
-                // Set the given effective visibility level to `Level::Direct` and
-                // sets the rest of the `use` chain to `Level::Reexported` until
-                // we hit the actual exported item.
-                //
-                // If the binding is ambiguous, put the root ambiguity binding and all reexports
-                // leading to it into the table. They are used by the `ambiguous_glob_reexports`
-                // lint. For all bindings added to the table this way `is_ambiguity` returns true.
-                let is_ambiguity =
-                    |binding: NameBinding<'ra>, warn: bool| binding.ambiguity.is_some() && !warn;
-                let mut parent_id = ParentId::Def(module_id);
-                let mut warn_ambiguity = binding.warn_ambiguity;
-                while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind {
-                    self.update_import(binding, parent_id);
+            let Some(mut binding) = name_resolution.borrow().binding() else {
+                continue;
+            };
+            // Set the given effective visibility level to `Level::Direct` and
+            // sets the rest of the `use` chain to `Level::Reexported` until
+            // we hit the actual exported item.
+            //
+            // If the binding is ambiguous, put the root ambiguity binding and all reexports
+            // leading to it into the table. They are used by the `ambiguous_glob_reexports`
+            // lint. For all bindings added to the table this way `is_ambiguity` returns true.
+            let is_ambiguity =
+                |binding: NameBinding<'ra>, warn: bool| binding.ambiguity.is_some() && !warn;
+            let mut parent_id = ParentId::Def(module_id);
+            let mut warn_ambiguity = binding.warn_ambiguity;
+            while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind {
+                self.update_import(binding, parent_id);
 
-                    if is_ambiguity(binding, warn_ambiguity) {
-                        // Stop at the root ambiguity, further bindings in the chain should not
-                        // be reexported because the root ambiguity blocks any access to them.
-                        // (Those further bindings are most likely not ambiguities themselves.)
-                        break;
-                    }
-
-                    parent_id = ParentId::Import(binding);
-                    binding = nested_binding;
-                    warn_ambiguity |= nested_binding.warn_ambiguity;
-                }
-                if !is_ambiguity(binding, warn_ambiguity)
-                    && let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local())
-                {
-                    self.update_def(def_id, binding.vis.expect_local(), parent_id);
+                if is_ambiguity(binding, warn_ambiguity) {
+                    // Stop at the root ambiguity, further bindings in the chain should not
+                    // be reexported because the root ambiguity blocks any access to them.
+                    // (Those further bindings are most likely not ambiguities themselves.)
+                    break;
                 }
+
+                parent_id = ParentId::Import(binding);
+                binding = nested_binding;
+                warn_ambiguity |= nested_binding.warn_ambiguity;
+            }
+            if !is_ambiguity(binding, warn_ambiguity)
+                && let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local())
+            {
+                self.update_def(def_id, binding.vis.expect_local(), parent_id);
             }
         }
     }
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 45e87edc53e..a3d3e87ade0 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -246,23 +246,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         // ---- end
         // ```
         // So we have to fall back to the module's parent during lexical resolution in this case.
-        if derive_fallback_lint_id.is_some() {
-            if let Some(parent) = module.parent {
-                // Inner module is inside the macro, parent module is outside of the macro.
-                if module.expansion != parent.expansion
-                    && module.expansion.is_descendant_of(parent.expansion)
-                {
-                    // The macro is a proc macro derive
-                    if let Some(def_id) = module.expansion.expn_data().macro_def_id {
-                        let ext = &self.get_macro_by_def_id(def_id).ext;
-                        if ext.builtin_name.is_none()
-                            && ext.macro_kind() == MacroKind::Derive
-                            && parent.expansion.outer_expn_is_descendant_of(*ctxt)
-                        {
-                            return Some((parent, derive_fallback_lint_id));
-                        }
-                    }
-                }
+        if derive_fallback_lint_id.is_some()
+            && let Some(parent) = module.parent
+            // Inner module is inside the macro
+            && module.expansion != parent.expansion
+            // Parent module is outside of the macro
+            && module.expansion.is_descendant_of(parent.expansion)
+            // The macro is a proc macro derive
+            && let Some(def_id) = module.expansion.expn_data().macro_def_id
+        {
+            let ext = &self.get_macro_by_def_id(def_id).ext;
+            if ext.builtin_name.is_none()
+                && ext.macro_kind() == MacroKind::Derive
+                && parent.expansion.outer_expn_is_descendant_of(*ctxt)
+            {
+                return Some((parent, derive_fallback_lint_id));
             }
         }
 
@@ -593,8 +591,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     },
                     Scope::StdLibPrelude => {
                         let mut result = Err(Determinacy::Determined);
-                        if let Some(prelude) = this.prelude {
-                            if let Ok(binding) = this.resolve_ident_in_module_unadjusted(
+                        if let Some(prelude) = this.prelude
+                            && let Ok(binding) = this.resolve_ident_in_module_unadjusted(
                                 ModuleOrUniformRoot::Module(prelude),
                                 ident,
                                 ns,
@@ -603,14 +601,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                                 None,
                                 ignore_binding,
                                 ignore_import,
-                            ) {
-                                if matches!(use_prelude, UsePrelude::Yes)
-                                    || this.is_builtin_macro(binding.res())
-                                {
-                                    result = Ok((binding, Flags::MISC_FROM_PRELUDE));
-                                }
-                            }
+                            )
+                            && (matches!(use_prelude, UsePrelude::Yes)
+                                || this.is_builtin_macro(binding.res()))
+                        {
+                            result = Ok((binding, Flags::MISC_FROM_PRELUDE));
                         }
+
                         result
                     }
                     Scope::BuiltinTypes => match this.builtin_types_bindings.get(&ident.name) {
@@ -939,10 +936,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         };
 
         // Items and single imports are not shadowable, if we have one, then it's determined.
-        if let Some(binding) = binding {
-            if !binding.is_glob_import() {
-                return check_usable(self, binding);
-            }
+        if let Some(binding) = binding
+            && !binding.is_glob_import()
+        {
+            return check_usable(self, binding);
         }
 
         // --- From now on we either have a glob resolution or no resolution. ---
@@ -1437,13 +1434,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         for (segment_idx, &Segment { ident, id, .. }) in path.iter().enumerate() {
             debug!("resolve_path ident {} {:?} {:?}", segment_idx, ident, id);
             let record_segment_res = |this: &mut Self, res| {
-                if finalize.is_some() {
-                    if let Some(id) = id {
-                        if !this.partial_res_map.contains_key(&id) {
-                            assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id");
-                            this.record_partial_res(id, PartialRes::new(res));
-                        }
-                    }
+                if finalize.is_some()
+                    && let Some(id) = id
+                    && !this.partial_res_map.contains_key(&id)
+                {
+                    assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id");
+                    this.record_partial_res(id, PartialRes::new(res));
                 }
             };
 
@@ -1463,13 +1459,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                             _ => None,
                         },
                     };
-                    if let Some(self_module) = self_module {
-                        if let Some(parent) = self_module.parent {
-                            module = Some(ModuleOrUniformRoot::Module(
-                                self.resolve_self(&mut ctxt, parent),
-                            ));
-                            continue;
-                        }
+                    if let Some(self_module) = self_module
+                        && let Some(parent) = self_module.parent
+                    {
+                        module =
+                            Some(ModuleOrUniformRoot::Module(self.resolve_self(&mut ctxt, parent)));
+                        continue;
                     }
                     return PathResult::failed(
                         ident,
@@ -1644,13 +1639,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 }
                 Err(Undetermined) => return PathResult::Indeterminate,
                 Err(Determined) => {
-                    if let Some(ModuleOrUniformRoot::Module(module)) = module {
-                        if opt_ns.is_some() && !module.is_normal() {
-                            return PathResult::NonModule(PartialRes::with_unresolved_segments(
-                                module.res().unwrap(),
-                                path.len() - segment_idx,
-                            ));
-                        }
+                    if let Some(ModuleOrUniformRoot::Module(module)) = module
+                        && opt_ns.is_some()
+                        && !module.is_normal()
+                    {
+                        return PathResult::NonModule(PartialRes::with_unresolved_segments(
+                            module.res().unwrap(),
+                            path.len() - segment_idx,
+                        ));
                     }
 
                     return PathResult::failed(
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index cad45d3c293..d555c938770 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -287,12 +287,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             binding.vis
         };
 
-        if let ImportKind::Glob { ref max_vis, .. } = import.kind {
-            if vis == import_vis
-                || max_vis.get().map_or(true, |max_vis| vis.is_at_least(max_vis, self.tcx))
-            {
-                max_vis.set(Some(vis.expect_local()))
-            }
+        if let ImportKind::Glob { ref max_vis, .. } = import.kind
+            && (vis == import_vis
+                || max_vis.get().is_none_or(|max_vis| vis.is_at_least(max_vis, self.tcx)))
+        {
+            max_vis.set(Some(vis.expect_local()))
         }
 
         self.arenas.alloc_name_binding(NameBindingData {
@@ -543,31 +542,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             // resolution for it so that later resolve stages won't complain.
             self.import_dummy_binding(*import, is_indeterminate);
 
-            if let Some(err) = unresolved_import_error {
-                glob_error |= import.is_glob();
+            let Some(err) = unresolved_import_error else { continue };
 
-                if let ImportKind::Single { source, ref source_bindings, .. } = import.kind {
-                    if source.name == kw::SelfLower {
-                        // Silence `unresolved import` error if E0429 is already emitted
-                        if let Err(Determined) = source_bindings.value_ns.get() {
-                            continue;
-                        }
-                    }
-                }
+            glob_error |= import.is_glob();
 
-                if prev_root_id != NodeId::ZERO
-                    && prev_root_id != import.root_id
-                    && !errors.is_empty()
-                {
-                    // In the case of a new import line, throw a diagnostic message
-                    // for the previous line.
-                    self.throw_unresolved_import_error(errors, glob_error);
-                    errors = vec![];
-                }
-                if seen_spans.insert(err.span) {
-                    errors.push((*import, err));
-                    prev_root_id = import.root_id;
-                }
+            if let ImportKind::Single { source, ref source_bindings, .. } = import.kind
+                && source.name == kw::SelfLower
+                // Silence `unresolved import` error if E0429 is already emitted
+                && let Err(Determined) = source_bindings.value_ns.get()
+            {
+                continue;
+            }
+
+            if prev_root_id != NodeId::ZERO && prev_root_id != import.root_id && !errors.is_empty()
+            {
+                // In the case of a new import line, throw a diagnostic message
+                // for the previous line.
+                self.throw_unresolved_import_error(errors, glob_error);
+                errors = vec![];
+            }
+            if seen_spans.insert(err.span) {
+                errors.push((*import, err));
+                prev_root_id = import.root_id;
             }
         }
 
@@ -609,60 +605,60 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             for (key, resolution) in self.resolutions(*module).borrow().iter() {
                 let resolution = resolution.borrow();
 
-                if let Some(binding) = resolution.binding {
-                    if let NameBindingKind::Import { import, .. } = binding.kind
-                        && let Some((amb_binding, _)) = binding.ambiguity
-                        && binding.res() != Res::Err
-                        && exported_ambiguities.contains(&binding)
+                let Some(binding) = resolution.binding else { continue };
+
+                if let NameBindingKind::Import { import, .. } = binding.kind
+                    && let Some((amb_binding, _)) = binding.ambiguity
+                    && binding.res() != Res::Err
+                    && exported_ambiguities.contains(&binding)
+                {
+                    self.lint_buffer.buffer_lint(
+                        AMBIGUOUS_GLOB_REEXPORTS,
+                        import.root_id,
+                        import.root_span,
+                        BuiltinLintDiag::AmbiguousGlobReexports {
+                            name: key.ident.to_string(),
+                            namespace: key.ns.descr().to_string(),
+                            first_reexport_span: import.root_span,
+                            duplicate_reexport_span: amb_binding.span,
+                        },
+                    );
+                }
+
+                if let Some(glob_binding) = resolution.shadowed_glob {
+                    let binding_id = match binding.kind {
+                        NameBindingKind::Res(res) => {
+                            Some(self.def_id_to_node_id[res.def_id().expect_local()])
+                        }
+                        NameBindingKind::Module(module) => {
+                            Some(self.def_id_to_node_id[module.def_id().expect_local()])
+                        }
+                        NameBindingKind::Import { import, .. } => import.id(),
+                    };
+
+                    if binding.res() != Res::Err
+                        && glob_binding.res() != Res::Err
+                        && let NameBindingKind::Import { import: glob_import, .. } =
+                            glob_binding.kind
+                        && let Some(binding_id) = binding_id
+                        && let Some(glob_import_id) = glob_import.id()
+                        && let glob_import_def_id = self.local_def_id(glob_import_id)
+                        && self.effective_visibilities.is_exported(glob_import_def_id)
+                        && glob_binding.vis.is_public()
+                        && !binding.vis.is_public()
                     {
                         self.lint_buffer.buffer_lint(
-                            AMBIGUOUS_GLOB_REEXPORTS,
-                            import.root_id,
-                            import.root_span,
-                            BuiltinLintDiag::AmbiguousGlobReexports {
-                                name: key.ident.to_string(),
-                                namespace: key.ns.descr().to_string(),
-                                first_reexport_span: import.root_span,
-                                duplicate_reexport_span: amb_binding.span,
+                            HIDDEN_GLOB_REEXPORTS,
+                            binding_id,
+                            binding.span,
+                            BuiltinLintDiag::HiddenGlobReexports {
+                                name: key.ident.name.to_string(),
+                                namespace: key.ns.descr().to_owned(),
+                                glob_reexport_span: glob_binding.span,
+                                private_item_span: binding.span,
                             },
                         );
                     }
-
-                    if let Some(glob_binding) = resolution.shadowed_glob {
-                        let binding_id = match binding.kind {
-                            NameBindingKind::Res(res) => {
-                                Some(self.def_id_to_node_id[res.def_id().expect_local()])
-                            }
-                            NameBindingKind::Module(module) => {
-                                Some(self.def_id_to_node_id[module.def_id().expect_local()])
-                            }
-                            NameBindingKind::Import { import, .. } => import.id(),
-                        };
-
-                        if binding.res() != Res::Err
-                            && glob_binding.res() != Res::Err
-                            && let NameBindingKind::Import { import: glob_import, .. } =
-                                glob_binding.kind
-                            && let Some(binding_id) = binding_id
-                            && let Some(glob_import_id) = glob_import.id()
-                            && let glob_import_def_id = self.local_def_id(glob_import_id)
-                            && self.effective_visibilities.is_exported(glob_import_def_id)
-                            && glob_binding.vis.is_public()
-                            && !binding.vis.is_public()
-                        {
-                            self.lint_buffer.buffer_lint(
-                                HIDDEN_GLOB_REEXPORTS,
-                                binding_id,
-                                binding.span,
-                                BuiltinLintDiag::HiddenGlobReexports {
-                                    name: key.ident.name.to_string(),
-                                    namespace: key.ns.descr().to_owned(),
-                                    glob_reexport_span: glob_binding.span,
-                                    private_item_span: binding.span,
-                                },
-                            );
-                        }
-                    }
                 }
             }
         }
@@ -1006,21 +1002,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         self.lint_if_path_starts_with_module(Some(finalize), &full_path, None);
                     }
 
-                    if let ModuleOrUniformRoot::Module(module) = module {
-                        if module == import.parent_scope.module {
-                            // Importing a module into itself is not allowed.
-                            return Some(UnresolvedImportError {
-                                span: import.span,
-                                label: Some(String::from(
-                                    "cannot glob-import a module into itself",
-                                )),
-                                note: None,
-                                suggestion: None,
-                                candidates: None,
-                                segment: None,
-                                module: None,
-                            });
-                        }
+                    if let ModuleOrUniformRoot::Module(module) = module
+                        && module == import.parent_scope.module
+                    {
+                        // Importing a module into itself is not allowed.
+                        return Some(UnresolvedImportError {
+                            span: import.span,
+                            label: Some(String::from("cannot glob-import a module into itself")),
+                            note: None,
+                            suggestion: None,
+                            candidates: None,
+                            segment: None,
+                            module: None,
+                        });
                     }
                     if !is_prelude
                         && let Some(max_vis) = max_vis.get()
@@ -1081,18 +1075,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         // Consistency checks, analogous to `finalize_macro_resolutions`.
                         let initial_res = source_bindings[ns].get().map(|initial_binding| {
                             all_ns_err = false;
-                            if let Some(target_binding) = target_bindings[ns].get() {
-                                if target.name == kw::Underscore
-                                    && initial_binding.is_extern_crate()
-                                    && !initial_binding.is_import()
-                                {
-                                    let used = if import.module_path.is_empty() {
-                                        Used::Scope
-                                    } else {
-                                        Used::Other
-                                    };
-                                    this.record_use(ident, target_binding, used);
-                                }
+                            if let Some(target_binding) = target_bindings[ns].get()
+                                && target.name == kw::Underscore
+                                && initial_binding.is_extern_crate()
+                                && !initial_binding.is_import()
+                            {
+                                let used = if import.module_path.is_empty() {
+                                    Used::Scope
+                                } else {
+                                    Used::Other
+                                };
+                                this.record_use(ident, target_binding, used);
                             }
                             initial_binding.res()
                         });
@@ -1247,17 +1240,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         let mut any_successful_reexport = false;
         let mut crate_private_reexport = false;
         self.per_ns(|this, ns| {
-            if let Ok(binding) = source_bindings[ns].get() {
-                if !binding.vis.is_at_least(import.vis, this.tcx) {
-                    reexport_error = Some((ns, binding));
-                    if let ty::Visibility::Restricted(binding_def_id) = binding.vis {
-                        if binding_def_id.is_top_level_module() {
-                            crate_private_reexport = true;
-                        }
-                    }
-                } else {
-                    any_successful_reexport = true;
+            let Ok(binding) = source_bindings[ns].get() else {
+                return;
+            };
+
+            if !binding.vis.is_at_least(import.vis, this.tcx) {
+                reexport_error = Some((ns, binding));
+                if let ty::Visibility::Restricted(binding_def_id) = binding.vis
+                    && binding_def_id.is_top_level_module()
+                {
+                    crate_private_reexport = true;
                 }
+            } else {
+                any_successful_reexport = true;
             }
         });
 
@@ -1474,28 +1469,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         // Since import resolution is finished, globs will not define any more names.
         *module.globs.borrow_mut() = Vec::new();
 
-        if let Some(def_id) = module.opt_def_id() {
-            let mut children = Vec::new();
-
-            module.for_each_child(self, |this, ident, _, binding| {
-                let res = binding.res().expect_non_local();
-                let error_ambiguity = binding.is_ambiguity_recursive() && !binding.warn_ambiguity;
-                if res != def::Res::Err && !error_ambiguity {
-                    let mut reexport_chain = SmallVec::new();
-                    let mut next_binding = binding;
-                    while let NameBindingKind::Import { binding, import, .. } = next_binding.kind {
-                        reexport_chain.push(import.simplify(this));
-                        next_binding = binding;
-                    }
+        let Some(def_id) = module.opt_def_id() else { return };
+
+        let mut children = Vec::new();
 
-                    children.push(ModChild { ident, res, vis: binding.vis, reexport_chain });
+        module.for_each_child(self, |this, ident, _, binding| {
+            let res = binding.res().expect_non_local();
+            let error_ambiguity = binding.is_ambiguity_recursive() && !binding.warn_ambiguity;
+            if res != def::Res::Err && !error_ambiguity {
+                let mut reexport_chain = SmallVec::new();
+                let mut next_binding = binding;
+                while let NameBindingKind::Import { binding, import, .. } = next_binding.kind {
+                    reexport_chain.push(import.simplify(this));
+                    next_binding = binding;
                 }
-            });
 
-            if !children.is_empty() {
-                // Should be fine because this code is only called for local modules.
-                self.module_children.insert(def_id.expect_local(), children);
+                children.push(ModChild { ident, res, vis: binding.vis, reexport_chain });
             }
+        });
+
+        if !children.is_empty() {
+            // Should be fine because this code is only called for local modules.
+            self.module_children.insert(def_id.expect_local(), children);
         }
     }
 }
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index c4aeaf478bd..8bd40ed3a73 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -468,16 +468,12 @@ impl<'a> PathSource<'a> {
                     {
                         "external crate"
                     }
-                    ExprKind::Path(_, path) => {
-                        let mut msg = "function";
-                        if let Some(segment) = path.segments.iter().last() {
-                            if let Some(c) = segment.ident.to_string().chars().next() {
-                                if c.is_uppercase() {
-                                    msg = "function, tuple struct or tuple variant";
-                                }
-                            }
-                        }
-                        msg
+                    ExprKind::Path(_, path)
+                        if let Some(segment) = path.segments.last()
+                            && let Some(c) = segment.ident.to_string().chars().next()
+                            && c.is_uppercase() =>
+                    {
+                        "function, tuple struct or tuple variant"
                     }
                     _ => "function",
                 },
@@ -612,7 +608,7 @@ impl MaybeExported<'_> {
                 return vis.kind.is_pub();
             }
         };
-        def_id.map_or(true, |def_id| r.effective_visibilities.is_exported(def_id))
+        def_id.is_none_or(|def_id| r.effective_visibilities.is_exported(def_id))
     }
 }
 
@@ -1182,32 +1178,27 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
                 // namespace first, and if that fails we try again in the value namespace. If
                 // resolution in the value namespace succeeds, we have an generic const argument on
                 // our hands.
-                if let TyKind::Path(None, ref path) = ty.kind {
+                if let TyKind::Path(None, ref path) = ty.kind
                     // We cannot disambiguate multi-segment paths right now as that requires type
                     // checking.
-                    if path.is_potential_trivial_const_arg() {
-                        let mut check_ns = |ns| {
-                            self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns)
-                                .is_some()
-                        };
-                        if !check_ns(TypeNS) && check_ns(ValueNS) {
-                            self.resolve_anon_const_manual(
-                                true,
-                                AnonConstKind::ConstArg(IsRepeatExpr::No),
-                                |this| {
-                                    this.smart_resolve_path(
-                                        ty.id,
-                                        &None,
-                                        path,
-                                        PathSource::Expr(None),
-                                    );
-                                    this.visit_path(path, ty.id);
-                                },
-                            );
+                    && path.is_potential_trivial_const_arg()
+                {
+                    let mut check_ns = |ns| {
+                        self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns)
+                            .is_some()
+                    };
+                    if !check_ns(TypeNS) && check_ns(ValueNS) {
+                        self.resolve_anon_const_manual(
+                            true,
+                            AnonConstKind::ConstArg(IsRepeatExpr::No),
+                            |this| {
+                                this.smart_resolve_path(ty.id, &None, path, PathSource::Expr(None));
+                                this.visit_path(path, ty.id);
+                            },
+                        );
 
-                            self.diag_metadata.currently_processing_generic_args = prev;
-                            return;
-                        }
+                        self.diag_metadata.currently_processing_generic_args = prev;
+                        return;
                     }
                 }
 
@@ -1243,54 +1234,56 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
     }
 
     fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) {
-        if let Some(ref args) = path_segment.args {
-            match &**args {
-                GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, args),
-                GenericArgs::Parenthesized(p_args) => {
-                    // Probe the lifetime ribs to know how to behave.
-                    for rib in self.lifetime_ribs.iter().rev() {
-                        match rib.kind {
-                            // We are inside a `PolyTraitRef`. The lifetimes are
-                            // to be introduced in that (maybe implicit) `for<>` binder.
-                            LifetimeRibKind::Generics {
-                                binder,
-                                kind: LifetimeBinderKind::PolyTrait,
-                                ..
-                            } => {
-                                self.with_lifetime_rib(
-                                    LifetimeRibKind::AnonymousCreateParameter {
+        let Some(ref args) = path_segment.args else {
+            return;
+        };
+
+        match &**args {
+            GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, args),
+            GenericArgs::Parenthesized(p_args) => {
+                // Probe the lifetime ribs to know how to behave.
+                for rib in self.lifetime_ribs.iter().rev() {
+                    match rib.kind {
+                        // We are inside a `PolyTraitRef`. The lifetimes are
+                        // to be introduced in that (maybe implicit) `for<>` binder.
+                        LifetimeRibKind::Generics {
+                            binder,
+                            kind: LifetimeBinderKind::PolyTrait,
+                            ..
+                        } => {
+                            self.with_lifetime_rib(
+                                LifetimeRibKind::AnonymousCreateParameter {
+                                    binder,
+                                    report_in_path: false,
+                                },
+                                |this| {
+                                    this.resolve_fn_signature(
                                         binder,
-                                        report_in_path: false,
-                                    },
-                                    |this| {
-                                        this.resolve_fn_signature(
-                                            binder,
-                                            false,
-                                            p_args.inputs.iter().map(|ty| (None, &**ty)),
-                                            &p_args.output,
-                                        )
-                                    },
-                                );
-                                break;
-                            }
-                            // We have nowhere to introduce generics. Code is malformed,
-                            // so use regular lifetime resolution to avoid spurious errors.
-                            LifetimeRibKind::Item | LifetimeRibKind::Generics { .. } => {
-                                visit::walk_generic_args(self, args);
-                                break;
-                            }
-                            LifetimeRibKind::AnonymousCreateParameter { .. }
-                            | LifetimeRibKind::AnonymousReportError
-                            | LifetimeRibKind::StaticIfNoLifetimeInScope { .. }
-                            | LifetimeRibKind::Elided(_)
-                            | LifetimeRibKind::ElisionFailure
-                            | LifetimeRibKind::ConcreteAnonConst(_)
-                            | LifetimeRibKind::ConstParamTy => {}
+                                        false,
+                                        p_args.inputs.iter().map(|ty| (None, &**ty)),
+                                        &p_args.output,
+                                    )
+                                },
+                            );
+                            break;
+                        }
+                        // We have nowhere to introduce generics. Code is malformed,
+                        // so use regular lifetime resolution to avoid spurious errors.
+                        LifetimeRibKind::Item | LifetimeRibKind::Generics { .. } => {
+                            visit::walk_generic_args(self, args);
+                            break;
                         }
+                        LifetimeRibKind::AnonymousCreateParameter { .. }
+                        | LifetimeRibKind::AnonymousReportError
+                        | LifetimeRibKind::StaticIfNoLifetimeInScope { .. }
+                        | LifetimeRibKind::Elided(_)
+                        | LifetimeRibKind::ElisionFailure
+                        | LifetimeRibKind::ConcreteAnonConst(_)
+                        | LifetimeRibKind::ConstParamTy => {}
                     }
                 }
-                GenericArgs::ParenthesizedElided(_) => {}
             }
+            GenericArgs::ParenthesizedElided(_) => {}
         }
     }
 
@@ -1735,13 +1728,8 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         }
 
         let normalized_ident = ident.normalize_to_macros_2_0();
-        let mut outer_res = None;
-        for rib in lifetime_rib_iter {
-            if let Some((&outer, _)) = rib.bindings.get_key_value(&normalized_ident) {
-                outer_res = Some(outer);
-                break;
-            }
-        }
+        let outer_res = lifetime_rib_iter
+            .find_map(|rib| rib.bindings.get_key_value(&normalized_ident).map(|(&outer, _)| outer));
 
         self.emit_undeclared_lifetime_error(lifetime, outer_res);
         self.record_lifetime_res(lifetime.id, LifetimeRes::Error, LifetimeElisionCandidate::Named);
@@ -1808,23 +1796,21 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                 }
                 LifetimeRibKind::AnonymousReportError => {
                     if elided {
-                        let mut suggestion = None;
-                        for rib in self.lifetime_ribs[i..].iter().rev() {
+                        let suggestion = self.lifetime_ribs[i..].iter().rev().find_map(|rib| {
                             if let LifetimeRibKind::Generics {
                                 span,
                                 kind: LifetimeBinderKind::PolyTrait | LifetimeBinderKind::WhereBound,
                                 ..
-                            } = &rib.kind
+                            } = rib.kind
                             {
-                                suggestion =
-                                    Some(errors::ElidedAnonymousLivetimeReportErrorSuggestion {
-                                        lo: span.shrink_to_lo(),
-                                        hi: lifetime.ident.span.shrink_to_hi(),
-                                    });
-                                break;
+                                Some(errors::ElidedAnonymousLivetimeReportErrorSuggestion {
+                                    lo: span.shrink_to_lo(),
+                                    hi: lifetime.ident.span.shrink_to_hi(),
+                                })
+                            } else {
+                                None
                             }
-                        }
-
+                        });
                         // are we trying to use an anonymous lifetime
                         // on a non GAT associated trait type?
                         if !self.in_func_body
@@ -2460,12 +2446,12 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         for i in (0..self.label_ribs.len()).rev() {
             let rib = &self.label_ribs[i];
 
-            if let RibKind::MacroDefinition(def) = rib.kind {
+            if let RibKind::MacroDefinition(def) = rib.kind
                 // If an invocation of this macro created `ident`, give up on `ident`
                 // and switch to `ident`'s source from the macro definition.
-                if def == self.r.macro_def(label.span.ctxt()) {
-                    label.span.remove_mark();
-                }
+                && def == self.r.macro_def(label.span.ctxt())
+            {
+                label.span.remove_mark();
             }
 
             let ident = label.normalize_to_macro_rules();
@@ -2493,14 +2479,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
     /// Determine whether or not a label from the `rib_index`th label rib is reachable.
     fn is_label_valid_from_rib(&self, rib_index: usize) -> bool {
         let ribs = &self.label_ribs[rib_index + 1..];
-
-        for rib in ribs {
-            if rib.kind.is_label_barrier() {
-                return false;
-            }
-        }
-
-        true
+        ribs.iter().all(|rib| !rib.kind.is_label_barrier())
     }
 
     fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) {
@@ -3505,21 +3484,20 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
             self.visit_ty(&qself.ty);
         }
         self.visit_path(&delegation.path, delegation.id);
-        if let Some(body) = &delegation.body {
-            self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| {
-                // `PatBoundCtx` is not necessary in this context
-                let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
-
-                let span = delegation.path.segments.last().unwrap().ident.span;
-                this.fresh_binding(
-                    Ident::new(kw::SelfLower, span),
-                    delegation.id,
-                    PatternSource::FnParam,
-                    &mut bindings,
-                );
-                this.visit_block(body);
-            });
-        }
+        let Some(body) = &delegation.body else { return };
+        self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| {
+            // `PatBoundCtx` is not necessary in this context
+            let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
+
+            let span = delegation.path.segments.last().unwrap().ident.span;
+            this.fresh_binding(
+                Ident::new(kw::SelfLower, span),
+                delegation.id,
+                PatternSource::FnParam,
+                &mut bindings,
+            );
+            this.visit_block(body);
+        });
     }
 
     fn resolve_params(&mut self, params: &'ast [Param]) {
@@ -3960,7 +3938,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         match res {
             Res::SelfCtor(_) // See #70549.
             | Res::Def(
-                DefKind::Ctor(_, CtorKind::Const) | DefKind::Const | DefKind::ConstParam,
+                DefKind::Ctor(_, CtorKind::Const) | DefKind::Const | DefKind::AssocConst | DefKind::ConstParam,
                 _,
             ) if is_syntactic_ambiguity => {
                 // Disambiguate in favor of a unit struct/variant or constant pattern.
@@ -3969,7 +3947,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                 }
                 Some(res)
             }
-            Res::Def(DefKind::Ctor(..) | DefKind::Const | DefKind::Static { .. }, _) => {
+            Res::Def(DefKind::Ctor(..) | DefKind::Const | DefKind::AssocConst | DefKind::Static { .. }, _) => {
                 // This is unambiguously a fresh binding, either syntactically
                 // (e.g., `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves
                 // to something unusable as a pattern (e.g., constructor function),
@@ -4005,7 +3983,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                 );
                 None
             }
-            Res::Def(DefKind::Fn, _) | Res::Local(..) | Res::Err => {
+            Res::Def(DefKind::Fn | DefKind::AssocFn, _) | Res::Local(..) | Res::Err => {
                 // These entities are explicitly allowed to be shadowed by fresh bindings.
                 None
             }
@@ -5104,7 +5082,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
 fn def_id_matches_path(tcx: TyCtxt<'_>, mut def_id: DefId, expected_path: &[&str]) -> bool {
     let mut path = expected_path.iter().rev();
     while let (Some(parent), Some(next_step)) = (tcx.opt_parent(def_id), path.next()) {
-        if !tcx.opt_item_name(def_id).map_or(false, |n| n.as_str() == *next_step) {
+        if !tcx.opt_item_name(def_id).is_some_and(|n| n.as_str() == *next_step) {
             return false;
         }
         def_id = parent;
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 2936d722aa7..17c92c7b501 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1696,7 +1696,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
             ) => {
                 // Don't suggest macro if it's unstable.
                 let suggestable = def_id.is_local()
-                    || self.r.tcx.lookup_stability(def_id).map_or(true, |s| s.is_stable());
+                    || self.r.tcx.lookup_stability(def_id).is_none_or(|s| s.is_stable());
 
                 err.span_label(span, fallback_label.to_string());
 
@@ -2135,7 +2135,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                                 .r
                                 .delegation_fn_sigs
                                 .get(&self.r.local_def_id(assoc_item.id))
-                                .map_or(false, |sig| sig.has_self) =>
+                                .is_some_and(|sig| sig.has_self) =>
                         {
                             AssocSuggestion::MethodWithSelf { called }
                         }
@@ -2166,7 +2166,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                                     .r
                                     .delegation_fn_sigs
                                     .get(&def_id)
-                                    .map_or(false, |sig| sig.has_self),
+                                    .is_some_and(|sig| sig.has_self),
                                 None => self
                                     .r
                                     .tcx
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 8e457e68eec..3b18e480be4 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1242,7 +1242,7 @@ impl<'ra> ResolverArenas<'ra> {
             no_implicit_prelude,
         ))));
         let def_id = module.opt_def_id();
-        if def_id.map_or(true, |def_id| def_id.is_local()) {
+        if def_id.is_none_or(|def_id| def_id.is_local()) {
             self.local_modules.borrow_mut().push(module);
         }
         if let Some(def_id) = def_id {
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 25e35fead7e..4ff54f47435 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -6,15 +6,14 @@ use std::mem;
 
 use rustc_ast::attr::AttributeExt;
 use rustc_ast::expand::StrippedCfgItem;
-use rustc_ast::{self as ast, Crate, Inline, ItemKind, ModKind, NodeId, attr};
+use rustc_ast::{self as ast, Crate, NodeId, attr};
 use rustc_ast_pretty::pprust;
 use rustc_attr_parsing::StabilityLevel;
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, StashKey};
 use rustc_expand::base::{
-    Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension,
-    SyntaxExtensionKind,
+    DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, SyntaxExtensionKind,
 };
 use rustc_expand::compile_declarative_macro;
 use rustc_expand::expand::{
@@ -26,8 +25,8 @@ use rustc_middle::middle::stability;
 use rustc_middle::ty::{RegisteredTools, TyCtxt, Visibility};
 use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::lint::builtin::{
-    LEGACY_DERIVE_HELPERS, OUT_OF_SCOPE_MACRO_CALLS, SOFT_UNSTABLE,
-    UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_MACRO_RULES, UNUSED_MACROS,
+    LEGACY_DERIVE_HELPERS, OUT_OF_SCOPE_MACRO_CALLS, UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+    UNUSED_MACRO_RULES, UNUSED_MACROS,
 };
 use rustc_session::parse::feature_err;
 use rustc_span::edit_distance::edit_distance;
@@ -157,26 +156,6 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools {
     registered_tools
 }
 
-// Some feature gates for inner attributes are reported as lints for backward compatibility.
-fn soft_custom_inner_attributes_gate(path: &ast::Path, invoc: &Invocation) -> bool {
-    match &path.segments[..] {
-        // `#![test]`
-        [seg] if seg.ident.name == sym::test => return true,
-        // `#![rustfmt::skip]` on out-of-line modules
-        [seg1, seg2] if seg1.ident.name == sym::rustfmt && seg2.ident.name == sym::skip => {
-            if let InvocationKind::Attr { item, .. } = &invoc.kind {
-                if let Annotatable::Item(item) = item {
-                    if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, _, _)) = item.kind {
-                        return true;
-                    }
-                }
-            }
-        }
-        _ => {}
-    }
-    false
-}
-
 impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
     fn next_node_id(&mut self) -> NodeId {
         self.next_node_id()
@@ -317,7 +296,6 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
             parent_scope,
             node_id,
             force,
-            soft_custom_inner_attributes_gate(path, invoc),
             deleg_impl,
             looks_like_invoc_in_mod_inert_attr,
         )?;
@@ -549,7 +527,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         parent_scope: &ParentScope<'ra>,
         node_id: NodeId,
         force: bool,
-        soft_custom_inner_attributes_gate: bool,
         deleg_impl: Option<LocalDefId>,
         invoc_in_mod_inert_attr: Option<LocalDefId>,
     ) -> Result<(Lrc<SyntaxExtension>, Res), Indeterminate> {
@@ -667,22 +644,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 Res::NonMacroAttr(..) => false,
                 _ => unreachable!(),
             };
-            if soft_custom_inner_attributes_gate {
-                self.tcx.sess.psess.buffer_lint(
-                    SOFT_UNSTABLE,
-                    path.span,
-                    node_id,
-                    BuiltinLintDiag::InnerAttributeUnstable { is_macro },
-                );
+            let msg = if is_macro {
+                "inner macro attributes are unstable"
             } else {
-                // FIXME: deduplicate with rustc_lint (`BuiltinLintDiag::InnerAttributeUnstable`)
-                let msg = if is_macro {
-                    "inner macro attributes are unstable"
-                } else {
-                    "custom inner attributes are unstable"
-                };
-                feature_err(&self.tcx.sess, sym::custom_inner_attributes, path.span, msg).emit();
-            }
+                "custom inner attributes are unstable"
+            };
+            feature_err(&self.tcx.sess, sym::custom_inner_attributes, path.span, msg).emit();
         }
 
         if res == Res::NonMacroAttr(NonMacroAttrKind::Tool)
@@ -1055,7 +1022,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         span: Span,
     ) {
         if let Some(Res::NonMacroAttr(kind)) = res {
-            if kind != NonMacroAttrKind::Tool && binding.map_or(true, |b| b.is_import()) {
+            if kind != NonMacroAttrKind::Tool && binding.is_none_or(|b| b.is_import()) {
                 let binding_span = binding.map(|binding| binding.span);
                 self.dcx().emit_err(errors::CannotUseThroughAnImport {
                     span,
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
index 7998596c59e..fecb9735019 100644
--- a/compiler/rustc_resolve/src/rustdoc.rs
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -350,10 +350,7 @@ pub fn strip_generics_from_path(path_str: &str) -> Result<Box<str>, MalformedGen
 /// If there are no doc-comments, return true.
 /// FIXME(#78591): Support both inner and outer attributes on the same item.
 pub fn inner_docs(attrs: &[impl AttributeExt]) -> bool {
-    attrs
-        .iter()
-        .find(|a| a.doc_str().is_some())
-        .map_or(true, |a| a.style() == ast::AttrStyle::Inner)
+    attrs.iter().find(|a| a.doc_str().is_some()).is_none_or(|a| a.style() == ast::AttrStyle::Inner)
 }
 
 /// Has `#[rustc_doc_primitive]` or `#[doc(keyword)]`.
diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml
index e9983699609..b9c535df4bd 100644
--- a/compiler/rustc_session/Cargo.toml
+++ b/compiler/rustc_session/Cargo.toml
@@ -31,7 +31,7 @@ libc = "0.2"
 # tidy-alphabetical-end
 
 [target.'cfg(windows)'.dependencies.windows]
-version = "0.57.0"
+version = "0.59.0"
 features = [
     "Win32_Foundation",
     "Win32_System_LibraryLoader",
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 21afb7df7cb..97bd2670aa6 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -675,7 +675,7 @@ impl OutputTypes {
 
     /// Returns `true` if user specified a name and not just produced type
     pub fn contains_explicit_name(&self, key: &OutputType) -> bool {
-        self.0.get(key).map_or(false, |f| f.is_some())
+        matches!(self.0.get(key), Some(Some(..)))
     }
 
     pub fn iter(&self) -> BTreeMapIter<'_, OutputType, Option<OutFileName>> {
@@ -888,7 +888,7 @@ impl Input {
             Input::File(file) => Some(file),
             Input::Str { name, .. } => match name {
                 FileName::Real(real) => real.local_path(),
-                FileName::QuoteExpansion(_) => None,
+                FileName::CfgSpec(_) => None,
                 FileName::Anon(_) => None,
                 FileName::MacroExpansion(_) => None,
                 FileName::ProcMacroSourceCode(_) => None,
@@ -1268,7 +1268,6 @@ pub enum EntryFnType {
         /// and an `include!()`.
         sigpipe: u8,
     },
-    Start,
 }
 
 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
@@ -1346,8 +1345,12 @@ pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg {
     user_cfg
 }
 
-pub fn build_target_config(early_dcx: &EarlyDiagCtxt, opts: &Options, sysroot: &Path) -> Target {
-    match Target::search(&opts.target_triple, sysroot) {
+pub fn build_target_config(
+    early_dcx: &EarlyDiagCtxt,
+    target: &TargetTuple,
+    sysroot: &Path,
+) -> Target {
+    match Target::search(target, sysroot) {
         Ok((target, warnings)) => {
             for warning in warnings.warning_messages() {
                 early_dcx.early_warn(warning)
@@ -1951,7 +1954,7 @@ fn collect_print_requests(
     matches: &getopts::Matches,
 ) -> Vec<PrintRequest> {
     let mut prints = Vec::<PrintRequest>::new();
-    if cg.target_cpu.as_ref().is_some_and(|s| s == "help") {
+    if cg.target_cpu.as_deref() == Some("help") {
         prints.push(PrintRequest { kind: PrintKind::TargetCPUs, out: OutFileName::Stdout });
         cg.target_cpu = None;
     };
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index 4be013fd6fd..ec83761da4a 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -145,7 +145,7 @@ fn current_dll_path() -> Result<PathBuf, String> {
     .map_err(|e| e.to_string())?;
 
     let mut filename = vec![0; 1024];
-    let n = unsafe { GetModuleFileNameW(module, &mut filename) } as usize;
+    let n = unsafe { GetModuleFileNameW(Some(module), &mut filename) } as usize;
     if n == 0 {
         return Err(format!("GetModuleFileNameW failed: {}", io::Error::last_os_error()));
     }
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 60f1154dc6d..10f1ce376ef 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -189,7 +189,7 @@ pub struct Session {
     /// enabled. Makes it so that "please report a bug" is hidden, as ICEs with
     /// internal features are wontfix, and they are usually the cause of the ICEs.
     /// None signifies that this is not tracked.
-    pub using_internal_features: Arc<AtomicBool>,
+    pub using_internal_features: &'static AtomicBool,
 
     /// 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
@@ -966,7 +966,7 @@ pub fn build_session(
     sysroot: PathBuf,
     cfg_version: &'static str,
     ice_file: Option<PathBuf>,
-    using_internal_features: Arc<AtomicBool>,
+    using_internal_features: &'static AtomicBool,
     expanded_args: Vec<String>,
 ) -> Session {
     // FIXME: This is not general enough to make the warning lint completely override
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index dc63ea1999e..ad38ea228bf 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -316,7 +316,7 @@ macro_rules! optional {
 #[doc(hidden)]
 macro_rules! run_driver {
     ($args:expr, $callback:expr $(, $with_tcx:ident)?) => {{
-        use rustc_driver::{Callbacks, Compilation, RunCompiler};
+        use rustc_driver::{Callbacks, Compilation, run_compiler};
         use rustc_middle::ty::TyCtxt;
         use rustc_interface::interface;
         use stable_mir::CompilerError;
@@ -347,7 +347,7 @@ macro_rules! run_driver {
             /// Runs the compiler against given target and tests it with `test_function`
             pub fn run(&mut self) -> Result<C, CompilerError<B>> {
                 let compiler_result = rustc_driver::catch_fatal_errors(|| -> interface::Result::<()> {
-                    RunCompiler::new(&self.args.clone(), self).run();
+                    run_compiler(&self.args.clone(), self);
                     Ok(())
                 });
                 match (compiler_result, self.result.take()) {
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
index de933952c6a..a5a17b4b573 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -181,6 +181,7 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
             RawPtr(mutability, place) => {
                 stable_mir::mir::Rvalue::AddressOf(mutability.stable(tables), place.stable(tables))
             }
+            Len(place) => stable_mir::mir::Rvalue::Len(place.stable(tables)),
             Cast(cast_kind, op, ty) => stable_mir::mir::Rvalue::Cast(
                 cast_kind.stable(tables),
                 op.stable(tables),
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 3cdae437b7d..a5826137181 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -1163,9 +1163,6 @@ pub enum DesugaringKind {
     WhileLoop,
     /// `async Fn()` bound modifier
     BoundModifier,
-    /// Marks a `&raw const *_1` needed as part of getting the length of a mutable
-    /// slice for the bounds check, so that MIRI's retag handling can recognize it.
-    IndexBoundsCheckReborrow,
 }
 
 impl DesugaringKind {
@@ -1182,7 +1179,6 @@ impl DesugaringKind {
             DesugaringKind::ForLoop => "`for` loop",
             DesugaringKind::WhileLoop => "`while` loop",
             DesugaringKind::BoundModifier => "trait bound modifier",
-            DesugaringKind::IndexBoundsCheckReborrow => "slice indexing",
         }
     }
 }
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 51cfbf59471..51d809bd65d 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -25,6 +25,7 @@
 #![feature(hash_set_entry)]
 #![feature(if_let_guard)]
 #![feature(let_chains)]
+#![feature(map_try_insert)]
 #![feature(negative_impls)]
 #![feature(read_buf)]
 #![feature(round_char_boundary)]
@@ -85,9 +86,9 @@ use std::str::FromStr;
 use std::{fmt, iter};
 
 use md5::{Digest, Md5};
-use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{Hash64, Hash128, HashStable, StableHasher};
 use rustc_data_structures::sync::{FreezeLock, FreezeWriteGuard, Lock, Lrc};
+use rustc_data_structures::unord::UnordMap;
 use sha1::Sha1;
 use sha2::Sha256;
 
@@ -103,7 +104,7 @@ pub struct SessionGlobals {
     span_interner: Lock<span_encoding::SpanInterner>,
     /// Maps a macro argument token into use of the corresponding metavariable in the macro body.
     /// Collisions are possible and processed in `maybe_use_metavar_location` on best effort basis.
-    metavar_spans: Lock<FxHashMap<Span, Span>>,
+    metavar_spans: MetavarSpansMap,
     hygiene_data: Lock<hygiene::HygieneData>,
 
     /// The session's source map, if there is one. This field should only be
@@ -177,9 +178,42 @@ pub fn create_default_session_globals_then<R>(f: impl FnOnce() -> R) -> R {
 // deserialization.
 scoped_tls::scoped_thread_local!(static SESSION_GLOBALS: SessionGlobals);
 
+#[derive(Default)]
+pub struct MetavarSpansMap(FreezeLock<UnordMap<Span, (Span, bool)>>);
+
+impl MetavarSpansMap {
+    pub fn insert(&self, span: Span, var_span: Span) -> bool {
+        match self.0.write().try_insert(span, (var_span, false)) {
+            Ok(_) => true,
+            Err(entry) => entry.entry.get().0 == var_span,
+        }
+    }
+
+    /// Read a span and record that it was read.
+    pub fn get(&self, span: Span) -> Option<Span> {
+        if let Some(mut mspans) = self.0.try_write() {
+            if let Some((var_span, read)) = mspans.get_mut(&span) {
+                *read = true;
+                Some(*var_span)
+            } else {
+                None
+            }
+        } else {
+            if let Some((span, true)) = self.0.read().get(&span) { Some(*span) } else { None }
+        }
+    }
+
+    /// Freeze the set, and return the spans which have been read.
+    ///
+    /// After this is frozen, no spans that have not been read can be read.
+    pub fn freeze_and_get_read_spans(&self) -> UnordMap<Span, Span> {
+        self.0.freeze().items().filter(|(_, (_, b))| *b).map(|(s1, (s2, _))| (*s1, *s2)).collect()
+    }
+}
+
 #[inline]
-pub fn with_metavar_spans<R>(f: impl FnOnce(&mut FxHashMap<Span, Span>) -> R) -> R {
-    with_session_globals(|session_globals| f(&mut session_globals.metavar_spans.lock()))
+pub fn with_metavar_spans<R>(f: impl FnOnce(&MetavarSpansMap) -> R) -> R {
+    with_session_globals(|session_globals| f(&session_globals.metavar_spans))
 }
 
 // FIXME: We should use this enum or something like it to get rid of the
@@ -305,8 +339,8 @@ impl RealFileName {
 #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash, Decodable, Encodable)]
 pub enum FileName {
     Real(RealFileName),
-    /// Call to `quote!`.
-    QuoteExpansion(Hash64),
+    /// Strings provided as `--cfg [cfgspec]`.
+    CfgSpec(Hash64),
     /// Command line.
     Anon(Hash64),
     /// Hack in `src/librustc_ast/parse.rs`.
@@ -353,7 +387,7 @@ impl fmt::Display for FileNameDisplay<'_> {
             Real(ref name) => {
                 write!(fmt, "{}", name.to_string_lossy(self.display_pref))
             }
-            QuoteExpansion(_) => write!(fmt, "<quote expansion>"),
+            CfgSpec(_) => write!(fmt, "<cfgspec>"),
             MacroExpansion(_) => write!(fmt, "<macro expansion>"),
             Anon(_) => write!(fmt, "<anon>"),
             ProcMacroSourceCode(_) => write!(fmt, "<proc-macro source code>"),
@@ -384,7 +418,7 @@ impl FileName {
             | ProcMacroSourceCode(_)
             | CliCrateAttr(_)
             | Custom(_)
-            | QuoteExpansion(_)
+            | CfgSpec(_)
             | DocTest(_, _)
             | InlineAsm(_) => false,
         }
@@ -425,7 +459,7 @@ impl FileName {
     pub fn cfg_spec_source_code(src: &str) -> FileName {
         let mut hasher = StableHasher::new();
         src.hash(&mut hasher);
-        FileName::QuoteExpansion(hasher.finish())
+        FileName::CfgSpec(hasher.finish())
     }
 
     pub fn cli_crate_attr_source_code(src: &str) -> FileName {
@@ -872,8 +906,7 @@ impl Span {
 
     /// Check if you can select metavar spans for the given spans to get matching contexts.
     fn try_metavars(a: SpanData, b: SpanData, a_orig: Span, b_orig: Span) -> (SpanData, SpanData) {
-        let get = |mspans: &FxHashMap<_, _>, s| mspans.get(&s).copied();
-        match with_metavar_spans(|mspans| (get(mspans, a_orig), get(mspans, b_orig))) {
+        match with_metavar_spans(|mspans| (mspans.get(a_orig), mspans.get(b_orig))) {
             (None, None) => {}
             (Some(meta_a), None) => {
                 let meta_a = meta_a.data();
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index b57b5df2609..f5ce5dbc9d6 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1287,6 +1287,7 @@ symbols! {
         mir_drop,
         mir_field,
         mir_goto,
+        mir_len,
         mir_make_place,
         mir_move,
         mir_offset,
diff --git a/compiler/rustc_target/src/callconv/powerpc64.rs b/compiler/rustc_target/src/callconv/powerpc64.rs
index 3a71592cbe0..92c1f6e7148 100644
--- a/compiler/rustc_target/src/callconv/powerpc64.rs
+++ b/compiler/rustc_target/src/callconv/powerpc64.rs
@@ -58,8 +58,10 @@ where
 
     // The AIX ABI expect byval for aggregates
     // See https://github.com/llvm/llvm-project/blob/main/clang/lib/CodeGen/Targets/PPC.cpp.
+    // The incoming parameter is represented as a pointer in the IR,
+    // the alignment is associated with the size of the register. (align 8 for 64bit)
     if !is_ret && abi == AIX {
-        arg.pass_by_stack_offset(None);
+        arg.pass_by_stack_offset(Some(Align::from_bytes(8).unwrap()));
         return;
     }
 
diff --git a/compiler/rustc_target/src/spec/base/windows_gnu.rs b/compiler/rustc_target/src/spec/base/windows_gnu.rs
index e975102e238..d8b6ae8cf32 100644
--- a/compiler/rustc_target/src/spec/base/windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/base/windows_gnu.rs
@@ -97,9 +97,9 @@ pub(crate) fn opts() -> TargetOptions {
         emit_debug_gdb_scripts: false,
         requires_uwtable: true,
         eh_frame_header: false,
+        debuginfo_kind: DebuginfoKind::Dwarf,
         // FIXME(davidtwco): Support Split DWARF on Windows GNU - may require LLVM changes to
         // output DWO, despite using DWARF, doesn't use ELF..
-        debuginfo_kind: DebuginfoKind::Pdb,
         supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
         ..Default::default()
     }
diff --git a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs
index 4f370ec8bd0..86e52117dbf 100644
--- a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs
+++ b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs
@@ -44,9 +44,9 @@ pub(crate) fn opts() -> TargetOptions {
         has_thread_local: true,
         crt_static_allows_dylibs: true,
         crt_static_respected: true,
+        debuginfo_kind: DebuginfoKind::Dwarf,
         // FIXME(davidtwco): Support Split DWARF on Windows GNU - may require LLVM changes to
         // output DWO, despite using DWARF, doesn't use ELF..
-        debuginfo_kind: DebuginfoKind::Pdb,
         supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
         ..Default::default()
     }
diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl
index b82bb27eb79..750d2756b4a 100644
--- a/compiler/rustc_trait_selection/messages.ftl
+++ b/compiler/rustc_trait_selection/messages.ftl
@@ -261,7 +261,6 @@ trait_selection_oc_fn_lang_correct_type = {$lang_item_name ->
         *[lang_item_name] lang item `{$lang_item_name}`
     } function has wrong type
 trait_selection_oc_fn_main_correct_type = `main` function has wrong type
-trait_selection_oc_fn_start_correct_type = `#[start]` function has wrong type
 trait_selection_oc_generic = mismatched types
 
 trait_selection_oc_if_else_different = `if` and `else` have incompatible types
@@ -396,7 +395,6 @@ trait_selection_subtype = ...so that the {$requirement ->
     [if_else_different] `if` and `else` have incompatible types
     [no_else] `if` missing an `else` returns `()`
     [fn_main_correct_type] `main` function has the correct type
-    [fn_start_correct_type] `#[start]` function has the correct type
     [fn_lang_correct_type] lang item function has the correct type
     [intrinsic_correct_type] intrinsic has the correct type
     [method_correct_type] method receiver has the correct type
@@ -410,7 +408,6 @@ trait_selection_subtype_2 = ...so that {$requirement ->
     [if_else_different] `if` and `else` have incompatible types
     [no_else] `if` missing an `else` returns `()`
     [fn_main_correct_type] `main` function has the correct type
-    [fn_start_correct_type] `#[start]` function has the correct type
     [fn_lang_correct_type] lang item function has the correct type
     [intrinsic_correct_type] intrinsic has the correct type
     [method_correct_type] method receiver has the correct type
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index 9778299eb19..1e9ef5e536c 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -2318,7 +2318,6 @@ impl<'tcx> ObligationCause<'tcx> {
             | ObligationCauseCode::MatchExpressionArm(_)
             | ObligationCauseCode::IfExpression { .. }
             | ObligationCauseCode::LetElse
-            | ObligationCauseCode::StartFunctionType
             | ObligationCauseCode::LangFunctionType(_)
             | ObligationCauseCode::IntrinsicType
             | ObligationCauseCode::MethodReceiver => FailureCode::Error0308,
@@ -2376,9 +2375,6 @@ impl<'tcx> ObligationCause<'tcx> {
             ObligationCauseCode::MainFunctionType => {
                 ObligationCauseFailureCode::FnMainCorrectType { span }
             }
-            ObligationCauseCode::StartFunctionType => {
-                ObligationCauseFailureCode::FnStartCorrectType { span, subdiags }
-            }
             &ObligationCauseCode::LangFunctionType(lang_item_name) => {
                 ObligationCauseFailureCode::FnLangCorrectType { span, subdiags, lang_item_name }
             }
@@ -2421,7 +2417,6 @@ impl<'tcx> ObligationCause<'tcx> {
                 "const is compatible with trait"
             }
             ObligationCauseCode::MainFunctionType => "`main` function has the correct type",
-            ObligationCauseCode::StartFunctionType => "`#[start]` function has the correct type",
             ObligationCauseCode::LangFunctionType(_) => "lang item function has the correct type",
             ObligationCauseCode::IntrinsicType => "intrinsic has the correct type",
             ObligationCauseCode::MethodReceiver => "method receiver has the correct type",
@@ -2442,7 +2437,6 @@ impl IntoDiagArg for ObligationCauseAsDiagArg<'_> {
                 "const_compat"
             }
             ObligationCauseCode::MainFunctionType => "fn_main_correct_type",
-            ObligationCauseCode::StartFunctionType => "fn_start_correct_type",
             ObligationCauseCode::LangFunctionType(_) => "fn_lang_correct_type",
             ObligationCauseCode::IntrinsicType => "intrinsic_correct_type",
             ObligationCauseCode::MethodReceiver => "method_correct_type",
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
index 3416a17624e..503090b5797 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
@@ -420,8 +420,8 @@ fn make_elided_region_spans_suggs<'a>(
 
     let mut process_consecutive_brackets =
         |span: Option<Span>, spans_suggs: &mut Vec<(Span, String)>| {
-            if span
-                .is_some_and(|span| bracket_span.map_or(true, |bracket_span| span == bracket_span))
+            if let Some(span) = span
+                && bracket_span.is_none_or(|bracket_span| span == bracket_span)
             {
                 consecutive_brackets += 1;
             } else if let Some(bracket_span) = bracket_span.take() {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
index 36270e0da78..21124cf20e5 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
@@ -167,6 +167,18 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             exp_span, exp_found.expected, exp_found.found,
         );
 
+        match self.tcx.coroutine_kind(cause.body_id) {
+            Some(hir::CoroutineKind::Desugared(
+                hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::AsyncGen,
+                _,
+            )) => (),
+            None
+            | Some(
+                hir::CoroutineKind::Coroutine(_)
+                | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _),
+            ) => return,
+        }
+
         if let ObligationCauseCode::CompareImplItem { .. } = cause.code() {
             return;
         }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
index fc0de13aeab..b4d294a70c0 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
@@ -172,14 +172,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         let bound_predicate = predicate.kind();
         let mut err = match bound_predicate.skip_binder() {
             ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
-                let trait_ref = bound_predicate.rebind(data.trait_ref);
-                debug!(?trait_ref);
+                let trait_pred = bound_predicate.rebind(data);
+                debug!(?trait_pred);
 
                 if let Err(e) = predicate.error_reported() {
                     return e;
                 }
 
-                if let Err(guar) = self.tcx.ensure().coherent_trait(trait_ref.def_id()) {
+                if let Err(guar) = self.tcx.ensure().coherent_trait(trait_pred.def_id()) {
                     // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
                     // other `Foo` impls are incoherent.
                     return guar;
@@ -200,13 +200,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 // avoid inundating the user with unnecessary errors, but we now
                 // check upstream for type errors and don't add the obligations to
                 // begin with in those cases.
-                if self.tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) {
+                if self.tcx.is_lang_item(trait_pred.def_id(), LangItem::Sized) {
                     match self.tainted_by_errors() {
                         None => {
                             let err = self.emit_inference_failure_err(
                                 obligation.cause.body_id,
                                 span,
-                                trait_ref.self_ty().skip_binder().into(),
+                                trait_pred.self_ty().skip_binder().into(),
                                 TypeAnnotationNeeded::E0282,
                                 false,
                             );
@@ -251,10 +251,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
                 let mut ambiguities = compute_applicable_impls_for_diagnostics(
                     self.infcx,
-                    &obligation.with(self.tcx, trait_ref),
+                    &obligation.with(self.tcx, trait_pred),
                 );
-                let has_non_region_infer =
-                    trait_ref.skip_binder().args.types().any(|t| !t.is_ty_or_numeric_infer());
+                let has_non_region_infer = trait_pred
+                    .skip_binder()
+                    .trait_ref
+                    .args
+                    .types()
+                    .any(|t| !t.is_ty_or_numeric_infer());
                 // It doesn't make sense to talk about applicable impls if there are more than a
                 // handful of them. If there are a lot of them, but only a few of them have no type
                 // params, we only show those, as they are more likely to be useful/intended.
@@ -294,7 +298,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     if impl_candidates.len() < 40 {
                         self.report_similar_impl_candidates(
                             impl_candidates.as_slice(),
-                            trait_ref,
+                            trait_pred,
                             obligation.cause.body_id,
                             &mut err,
                             false,
@@ -306,7 +310,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 if let ObligationCauseCode::WhereClause(def_id, _)
                 | ObligationCauseCode::WhereClauseInExpr(def_id, ..) = *obligation.cause.code()
                 {
-                    self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
+                    self.suggest_fully_qualified_path(&mut err, def_id, span, trait_pred.def_id());
                 }
 
                 if let Some(ty::GenericArgKind::Type(_)) = arg.map(|arg| arg.unpack())
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 6076c999086..bcd3b0109b7 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -23,9 +23,7 @@ use rustc_middle::ty::print::{
     FmtPrinter, Print, PrintPolyTraitPredicateExt, PrintTraitPredicateExt as _,
     PrintTraitRefExt as _, with_forced_trimmed_paths,
 };
-use rustc_middle::ty::{
-    self, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast,
-};
+use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast};
 use rustc_middle::{bug, span_bug};
 use rustc_span::{BytePos, DUMMY_SP, STDLIB_STABLE_CRATES, Span, Symbol, sym};
 use tracing::{debug, instrument};
@@ -155,12 +153,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             (leaf_trait_predicate, &obligation)
                         };
 
-                        let main_trait_ref = main_trait_predicate.to_poly_trait_ref();
-                        let leaf_trait_ref = leaf_trait_predicate.to_poly_trait_ref();
-
                         if let Some(guar) = self.emit_specialized_closure_kind_error(
                             &obligation,
-                            leaf_trait_ref,
+                            leaf_trait_predicate,
                         ) {
                             return guar;
                         }
@@ -202,14 +197,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         } = self.on_unimplemented_note(main_trait_predicate, main_obligation, &mut long_ty_file);
 
                         let have_alt_message = message.is_some() || label.is_some();
-                        let is_try_conversion = self.is_try_conversion(span, main_trait_ref.def_id());
+                        let is_try_conversion = self.is_try_conversion(span, main_trait_predicate.def_id());
                         let is_unsize =
-                            self.tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Unsize);
+                            self.tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Unsize);
                         let (message, notes, append_const_msg) = if is_try_conversion {
                             (
                                 Some(format!(
                                     "`?` couldn't convert the error to `{}`",
-                                    main_trait_ref.skip_binder().self_ty(),
+                                    main_trait_predicate.skip_binder().self_ty(),
                                 )),
                                 vec![
                                     "the question mark operation (`?`) implicitly performs a \
@@ -230,12 +225,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             post_message,
                         );
 
-                        let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item(main_trait_ref.def_id(), LangItem::TransmuteTrait)
+                        let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::TransmuteTrait)
                         {
                             // Recompute the safe transmute reason and use that for the error reporting
                             match self.get_safe_transmute_error_and_reason(
                                 obligation.clone(),
-                                main_trait_ref,
+                                main_trait_predicate,
                                 span,
                             ) {
                                 GetSafeTransmuteErrorAndReason::Silent => {
@@ -266,7 +261,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         }
                         let mut suggested = false;
                         if is_try_conversion {
-                            suggested = self.try_conversion_context(&obligation, main_trait_ref.skip_binder(), &mut err);
+                            suggested = self.try_conversion_context(&obligation, main_trait_predicate, &mut err);
                         }
 
                         if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) {
@@ -274,12 +269,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                                 ret_span,
                                 format!(
                                     "expected `{}` because of this",
-                                    main_trait_ref.skip_binder().self_ty()
+                                    main_trait_predicate.skip_binder().self_ty()
                                 ),
                             );
                         }
 
-                        if tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Tuple) {
+                        if tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Tuple) {
                             self.add_tuple_trait_message(
                                 obligation.cause.code().peel_derives(),
                                 &mut err,
@@ -319,7 +314,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             // If it has a custom `#[rustc_on_unimplemented]`
                             // error message, let's display it as the label!
                             err.span_label(span, s);
-                            if !matches!(leaf_trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) {
+                            if !matches!(leaf_trait_predicate.skip_binder().self_ty().kind(), ty::Param(_)) {
                                 // When the self type is a type param We don't need to "the trait
                                 // `std::marker::Sized` is not implemented for `T`" as we will point
                                 // at the type param with a label to suggest constraining it.
@@ -339,7 +334,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         if let ObligationCauseCode::Coercion { source, target } =
                             *obligation.cause.code().peel_derives()
                         {
-                            if self.tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Sized) {
+                            if self.tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Sized) {
                                 self.suggest_borrowing_for_object_cast(
                                     &mut err,
                                     root_obligation,
@@ -368,7 +363,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             err.span_label(tcx.def_span(body), s);
                         }
 
-                        self.suggest_floating_point_literal(&obligation, &mut err, leaf_trait_ref);
+                        self.suggest_floating_point_literal(&obligation, &mut err, leaf_trait_predicate);
                         self.suggest_dereferencing_index(&obligation, &mut err, leaf_trait_predicate);
                         suggested |= self.suggest_dereferences(&obligation, &mut err, leaf_trait_predicate);
                         suggested |= self.suggest_fn_call(&obligation, &mut err, leaf_trait_predicate);
@@ -376,7 +371,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         suggested = if let &[cand] = &impl_candidates[..] {
                             let cand = cand.trait_ref;
                             if let (ty::FnPtr(..), ty::FnDef(..)) =
-                                (cand.self_ty().kind(), main_trait_ref.self_ty().skip_binder().kind())
+                                (cand.self_ty().kind(), main_trait_predicate.self_ty().skip_binder().kind())
                             {
                                 // Wrap method receivers and `&`-references in parens
                                 let suggestion = if self.tcx.sess.source_map().span_look_ahead(span, ".", Some(50)).is_some() {
@@ -423,11 +418,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             span,
                             leaf_trait_predicate,
                         );
-                        self.note_version_mismatch(&mut err, leaf_trait_ref);
+                        self.note_version_mismatch(&mut err, leaf_trait_predicate);
                         self.suggest_remove_await(&obligation, &mut err);
                         self.suggest_derive(&obligation, &mut err, leaf_trait_predicate);
 
-                        if tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Try) {
+                        if tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Try) {
                             self.suggest_await_before_try(
                                 &mut err,
                                 &obligation,
@@ -455,9 +450,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             );
                         }
 
-                        let is_fn_trait = tcx.is_fn_trait(leaf_trait_ref.def_id());
+                        let is_fn_trait = tcx.is_fn_trait(leaf_trait_predicate.def_id());
                         let is_target_feature_fn = if let ty::FnDef(def_id, _) =
-                            *leaf_trait_ref.skip_binder().self_ty().kind()
+                            *leaf_trait_predicate.skip_binder().self_ty().kind()
                         {
                             !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
                         } else {
@@ -509,7 +504,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         }
 
                         self.explain_hrtb_projection(&mut err, leaf_trait_predicate, obligation.param_env, &obligation.cause);
-                        self.suggest_desugaring_async_fn_in_trait(&mut err, main_trait_ref);
+                        self.suggest_desugaring_async_fn_in_trait(&mut err, main_trait_predicate);
 
                         // Return early if the trait is Debug or Display and the invocation
                         // originates within a standard library macro, because the output
@@ -527,7 +522,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
                         if in_std_macro
                             && matches!(
-                                self.tcx.get_diagnostic_name(leaf_trait_ref.def_id()),
+                                self.tcx.get_diagnostic_name(leaf_trait_predicate.def_id()),
                                 Some(sym::Debug | sym::Display)
                             )
                         {
@@ -785,21 +780,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     fn emit_specialized_closure_kind_error(
         &self,
         obligation: &PredicateObligation<'tcx>,
-        mut trait_ref: ty::PolyTraitRef<'tcx>,
+        mut trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> Option<ErrorGuaranteed> {
         // If `AsyncFnKindHelper` is not implemented, that means that the closure kind
         // doesn't extend the goal kind. This is worth reporting, but we can only do so
         // if we actually know which closure this goal comes from, so look at the cause
         // to see if we can extract that information.
-        if self.tcx.is_lang_item(trait_ref.def_id(), LangItem::AsyncFnKindHelper)
-            && let Some(found_kind) = trait_ref.skip_binder().args.type_at(0).to_opt_closure_kind()
+        if self.tcx.is_lang_item(trait_pred.def_id(), LangItem::AsyncFnKindHelper)
+            && let Some(found_kind) =
+                trait_pred.skip_binder().trait_ref.args.type_at(0).to_opt_closure_kind()
             && let Some(expected_kind) =
-                trait_ref.skip_binder().args.type_at(1).to_opt_closure_kind()
+                trait_pred.skip_binder().trait_ref.args.type_at(1).to_opt_closure_kind()
             && !found_kind.extends(expected_kind)
         {
             if let Some((_, Some(parent))) = obligation.cause.code().parent_with_predicate() {
                 // If we have a derived obligation, then the parent will be a `AsyncFn*` goal.
-                trait_ref = parent.to_poly_trait_ref();
+                trait_pred = parent;
             } else if let &ObligationCauseCode::FunctionArg { arg_hir_id, .. } =
                 obligation.cause.code()
                 && let Some(typeck_results) = &self.typeck_results
@@ -820,9 +816,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }
         }
 
-        let self_ty = trait_ref.self_ty().skip_binder();
+        let self_ty = trait_pred.self_ty().skip_binder();
 
-        if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id()) {
+        if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_pred.def_id()) {
             let (closure_def_id, found_args, by_ref_captures) = match *self_ty.kind() {
                 ty::Closure(def_id, args) => {
                     (def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), None)
@@ -837,7 +833,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 _ => return None,
             };
 
-            let expected_args = trait_ref.map_bound(|trait_ref| trait_ref.args.type_at(1));
+            let expected_args =
+                trait_pred.map_bound(|trait_pred| trait_pred.trait_ref.args.type_at(1));
 
             // Verify that the arguments are compatible. If the signature is
             // mismatched, then we have a totally different error to report.
@@ -909,7 +906,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     fn try_conversion_context(
         &self,
         obligation: &PredicateObligation<'tcx>,
-        trait_ref: ty::TraitRef<'tcx>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
         err: &mut Diag<'_>,
     ) -> bool {
         let span = obligation.cause.span;
@@ -953,8 +950,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         if !self.tcx.is_diagnostic_item(sym::FromResidual, y.def_id()) {
             return false;
         }
-        let self_ty = trait_ref.self_ty();
-        let found_ty = trait_ref.args.get(1).and_then(|a| a.as_type());
+        let self_ty = trait_pred.skip_binder().self_ty();
+        let found_ty = trait_pred.skip_binder().trait_ref.args.get(1).and_then(|a| a.as_type());
 
         let mut prev_ty = self.resolve_vars_if_possible(
             typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
@@ -1223,18 +1220,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         goal: ty::TraitPredicate<'tcx>,
         assumption: ty::PolyTraitPredicate<'tcx>,
     ) -> bool {
+        // Fast path
         if goal.polarity != assumption.polarity() {
             return false;
         }
 
-        let trait_goal = goal.trait_ref;
         let trait_assumption = self.instantiate_binder_with_fresh_vars(
             DUMMY_SP,
             infer::BoundRegionConversionTime::HigherRankedType,
-            assumption.to_poly_trait_ref(),
+            assumption,
         );
 
-        self.can_eq(ty::ParamEnv::empty(), trait_goal, trait_assumption)
+        self.can_eq(ty::ParamEnv::empty(), goal.trait_ref, trait_assumption.trait_ref)
     }
 
     fn can_match_projection(
@@ -1341,20 +1338,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     let derive_better_type_error =
                         |alias_term: ty::AliasTerm<'tcx>, expected_term: ty::Term<'tcx>| {
                             let ocx = ObligationCtxt::new(self);
-                            let normalized_term = match expected_term.unpack() {
-                                ty::TermKind::Ty(_) => self.next_ty_var(DUMMY_SP).into(),
-                                ty::TermKind::Const(_) => self.next_const_var(DUMMY_SP).into(),
-                            };
-                            ocx.register_obligation(Obligation::new(
-                                self.tcx,
-                                ObligationCause::dummy(),
+
+                            let Ok(normalized_term) = ocx.structurally_normalize_term(
+                                &ObligationCause::dummy(),
                                 obligation.param_env,
-                                ty::PredicateKind::NormalizesTo(ty::NormalizesTo {
-                                    alias: alias_term,
-                                    term: normalized_term,
-                                }),
-                            ));
-                            let _ = ocx.select_where_possible();
+                                alias_term.to_term(self.tcx),
+                            ) else {
+                                return None;
+                            };
+
                             if let Err(terr) = ocx.eq(
                                 &ObligationCause::dummy(),
                                 obligation.param_env,
@@ -1682,7 +1674,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     pub(super) fn report_similar_impl_candidates(
         &self,
         impl_candidates: &[ImplCandidate<'tcx>],
-        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
         body_def_id: LocalDefId,
         err: &mut Diag<'_>,
         other: bool,
@@ -1727,7 +1719,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         // We'll check for the case where the reason for the mismatch is that the trait comes from
         // one crate version and the type comes from another crate version, even though they both
         // are from the same crate.
-        let trait_def_id = trait_ref.def_id();
+        let trait_def_id = trait_pred.def_id();
         let trait_name = self.tcx.item_name(trait_def_id);
         let crate_name = self.tcx.crate_name(trait_def_id.krate);
         if let Some(other_trait_def_id) = self.tcx.all_traits().find(|def_id| {
@@ -1739,7 +1731,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             // different crate `DefId`. We highlight the traits.
 
             let found_type =
-                if let ty::Adt(def, _) = trait_ref.self_ty().skip_binder().peel_refs().kind() {
+                if let ty::Adt(def, _) = trait_pred.self_ty().skip_binder().peel_refs().kind() {
                     Some(def.did())
                 } else {
                     None
@@ -1836,7 +1828,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             if self.probe(|_| {
                 let ocx = ObligationCtxt::new(self);
 
-                self.enter_forall(trait_ref, |obligation_trait_ref| {
+                self.enter_forall(trait_pred, |obligation_trait_ref| {
                     let impl_args = self.fresh_args_for_item(DUMMY_SP, single.impl_def_id);
                     let impl_trait_ref = ocx.normalize(
                         &ObligationCause::dummy(),
@@ -1864,7 +1856,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
                     let mut terrs = vec![];
                     for (obligation_arg, impl_arg) in
-                        std::iter::zip(obligation_trait_ref.args, impl_trait_ref.args)
+                        std::iter::zip(obligation_trait_ref.trait_ref.args, impl_trait_ref.args)
                     {
                         if (obligation_arg, impl_arg).references_error() {
                             return false;
@@ -1906,8 +1898,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     }
 
                     let traits = self.cmp_traits(
-                        obligation_trait_ref.def_id,
-                        &obligation_trait_ref.args[1..],
+                        obligation_trait_ref.def_id(),
+                        &obligation_trait_ref.trait_ref.args[1..],
                         impl_trait_ref.def_id,
                         &impl_trait_ref.args[1..],
                     );
@@ -1991,7 +1983,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }
             if let &[cand] = &candidates[..] {
                 let (desc, mention_castable) =
-                    match (cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind()) {
+                    match (cand.self_ty().kind(), trait_pred.self_ty().skip_binder().kind()) {
                         (ty::FnPtr(..), ty::FnDef(..)) => {
                             (" implemented for fn pointer `", ", cast using `as`")
                         }
@@ -2055,7 +2047,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             .filter(|cand| !self.tcx.do_not_recommend_impl(cand.impl_def_id))
             .collect::<Vec<_>>();
 
-        let def_id = trait_ref.def_id();
+        let def_id = trait_pred.def_id();
         if impl_candidates.is_empty() {
             if self.tcx.trait_is_auto(def_id)
                 || self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
@@ -2132,11 +2124,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             && !self.tcx.trait_is_auto(def_id)
             && !self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
         {
-            let trait_ref = trait_pred.to_poly_trait_ref();
             let impl_candidates = self.find_similar_impl_candidates(trait_pred);
             self.report_similar_impl_candidates(
                 &impl_candidates,
-                trait_ref,
+                trait_pred,
                 body_def_id,
                 err,
                 true,
@@ -2173,12 +2164,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
     /// with the same path as `trait_ref`, a help message about
     /// a probable version mismatch is added to `err`
-    fn note_version_mismatch(&self, err: &mut Diag<'_>, trait_ref: ty::PolyTraitRef<'tcx>) -> bool {
+    fn note_version_mismatch(
+        &self,
+        err: &mut Diag<'_>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
+    ) -> bool {
         let get_trait_impls = |trait_def_id| {
             let mut trait_impls = vec![];
             self.tcx.for_each_relevant_impl(
                 trait_def_id,
-                trait_ref.skip_binder().self_ty(),
+                trait_pred.skip_binder().self_ty(),
                 |impl_def_id| {
                     trait_impls.push(impl_def_id);
                 },
@@ -2186,11 +2181,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             trait_impls
         };
 
-        let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
+        let required_trait_path = self.tcx.def_path_str(trait_pred.def_id());
         let traits_with_same_path: UnordSet<_> = self
             .tcx
             .visible_traits()
-            .filter(|trait_def_id| *trait_def_id != trait_ref.def_id())
+            .filter(|trait_def_id| *trait_def_id != trait_pred.def_id())
             .map(|trait_def_id| (self.tcx.def_path_str(trait_def_id), trait_def_id))
             .filter(|(p, _)| *p == required_trait_path)
             .collect();
@@ -2374,7 +2369,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     fn get_safe_transmute_error_and_reason(
         &self,
         obligation: PredicateObligation<'tcx>,
-        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
         span: Span,
     ) -> GetSafeTransmuteErrorAndReason {
         use rustc_transmute::Answer;
@@ -2386,19 +2381,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }
 
             // Erase regions because layout code doesn't particularly care about regions.
-            let trait_ref =
-                self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref));
+            let trait_pred =
+                self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_pred));
 
             let src_and_dst = rustc_transmute::Types {
-                dst: trait_ref.args.type_at(0),
-                src: trait_ref.args.type_at(1),
+                dst: trait_pred.trait_ref.args.type_at(0),
+                src: trait_pred.trait_ref.args.type_at(1),
             };
 
             let ocx = ObligationCtxt::new(self);
             let Ok(assume) = ocx.structurally_normalize_const(
                 &obligation.cause,
                 obligation.param_env,
-                trait_ref.args.const_at(2),
+                trait_pred.trait_ref.args.const_at(2),
             ) else {
                 self.dcx().span_delayed_bug(
                     span,
@@ -2417,8 +2412,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 return GetSafeTransmuteErrorAndReason::Silent;
             };
 
-            let dst = trait_ref.args.type_at(0);
-            let src = trait_ref.args.type_at(1);
+            let dst = trait_pred.trait_ref.args.type_at(0);
+            let src = trait_pred.trait_ref.args.type_at(1);
             let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
 
             match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
@@ -2566,12 +2561,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 trait_predicate.skip_binder().polarity,
             )
         {
-            self.add_help_message_for_fn_trait(
-                trait_predicate.to_poly_trait_ref(),
-                err,
-                implemented_kind,
-                params,
-            );
+            self.add_help_message_for_fn_trait(trait_predicate, err, implemented_kind, params);
         } else if !trait_predicate.has_non_region_infer()
             && self.predicate_can_apply(obligation.param_env, trait_predicate)
         {
@@ -2606,7 +2596,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
             if !self.report_similar_impl_candidates(
                 &impl_candidates,
-                trait_predicate.to_poly_trait_ref(),
+                trait_predicate,
                 body_def_id,
                 err,
                 true,
@@ -2623,7 +2613,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             self.suggest_convert_to_slice(
                 err,
                 obligation,
-                trait_predicate.to_poly_trait_ref(),
+                trait_predicate,
                 impl_candidates.as_slice(),
                 span,
             );
@@ -2634,7 +2624,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
     fn add_help_message_for_fn_trait(
         &self,
-        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
         err: &mut Diag<'_>,
         implemented_kind: ty::ClosureKind,
         params: ty::Binder<'tcx, Ty<'tcx>>,
@@ -2647,12 +2637,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         // to implement.
         let selected_kind = self
             .tcx
-            .fn_trait_kind_from_def_id(trait_ref.def_id())
+            .fn_trait_kind_from_def_id(trait_pred.def_id())
             .expect("expected to map DefId to ClosureKind");
         if !implemented_kind.extends(selected_kind) {
             err.note(format!(
                 "`{}` implements `{}`, but it must implement `{}`, which is more general",
-                trait_ref.skip_binder().self_ty(),
+                trait_pred.skip_binder().self_ty(),
                 implemented_kind,
                 selected_kind
             ));
@@ -2660,7 +2650,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
         // Note any argument mismatches
         let given_ty = params.skip_binder();
-        let expected_ty = trait_ref.skip_binder().args.type_at(1);
+        let expected_ty = trait_pred.skip_binder().trait_ref.args.type_at(1);
         if let ty::Tuple(given) = given_ty.kind()
             && let ty::Tuple(expected) = expected_ty.kind()
         {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
index cd4f77bb4cf..f2bcc51e687 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
@@ -433,33 +433,19 @@ pub fn report_dyn_incompatibility<'tcx>(
         hir::Node::Item(item) => Some(item.ident.span),
         _ => None,
     });
+
     let mut err = struct_span_code_err!(
         tcx.dcx(),
         span,
         E0038,
-        "the trait `{}` cannot be made into an object",
+        "the {} `{}` is not dyn compatible",
+        tcx.def_descr(trait_def_id),
         trait_str
     );
-    err.span_label(span, format!("`{trait_str}` cannot be made into an object"));
-
-    if let Some(hir_id) = hir_id
-        && let hir::Node::Ty(ty) = tcx.hir_node(hir_id)
-        && let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind
-    {
-        let mut hir_id = hir_id;
-        while let hir::Node::Ty(ty) = tcx.parent_hir_node(hir_id) {
-            hir_id = ty.hir_id;
-        }
-        if tcx.parent_hir_node(hir_id).fn_sig().is_some() {
-            // Do not suggest `impl Trait` when dealing with things like super-traits.
-            err.span_suggestion_verbose(
-                ty.span.until(trait_ref.span),
-                "consider using an opaque type instead",
-                "impl ",
-                Applicability::MaybeIncorrect,
-            );
-        }
-    }
+    err.span_label(span, format!("`{trait_str}` is not dyn compatible"));
+
+    attempt_dyn_to_impl_suggestion(tcx, hir_id, &mut err);
+
     let mut reported_violations = FxIndexSet::default();
     let mut multi_span = vec![];
     let mut messages = vec![];
@@ -474,7 +460,7 @@ pub fn report_dyn_incompatibility<'tcx>(
         if reported_violations.insert(violation.clone()) {
             let spans = violation.spans();
             let msg = if trait_span.is_none() || spans.is_empty() {
-                format!("the trait cannot be made into an object because {}", violation.error_msg())
+                format!("the trait is not dyn compatible because {}", violation.error_msg())
             } else {
                 format!("...because {}", violation.error_msg())
             };
@@ -491,7 +477,7 @@ pub fn report_dyn_incompatibility<'tcx>(
     let has_multi_span = !multi_span.is_empty();
     let mut note_span = MultiSpan::from_spans(multi_span.clone());
     if let (Some(trait_span), true) = (trait_span, has_multi_span) {
-        note_span.push_span_label(trait_span, "this trait cannot be made into an object...");
+        note_span.push_span_label(trait_span, "this trait is not dyn compatible...");
     }
     for (span, msg) in iter::zip(multi_span, messages) {
         note_span.push_span_label(span, msg);
@@ -499,16 +485,12 @@ pub fn report_dyn_incompatibility<'tcx>(
     // FIXME(dyn_compat_renaming): Update the URL.
     err.span_note(
         note_span,
-        "for a trait to be \"dyn-compatible\" it needs to allow building a vtable to allow the call \
-         to be resolvable dynamically; for more information visit \
-         <https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
+        "for a trait to be dyn compatible it needs to allow building a vtable\n\
+        for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
     );
 
     // Only provide the help if its a local trait, otherwise it's not actionable.
     if trait_span.is_some() {
-        let mut reported_violations: Vec<_> = reported_violations.into_iter().collect();
-        reported_violations.sort();
-
         let mut potential_solutions: Vec<_> =
             reported_violations.into_iter().map(|violation| violation.solution()).collect();
         potential_solutions.sort();
@@ -519,68 +501,116 @@ pub fn report_dyn_incompatibility<'tcx>(
         }
     }
 
+    attempt_dyn_to_enum_suggestion(tcx, trait_def_id, &*trait_str, &mut err);
+
+    err
+}
+
+/// Attempt to suggest converting the `dyn Trait` argument to an enumeration
+/// over the types that implement `Trait`.
+fn attempt_dyn_to_enum_suggestion(
+    tcx: TyCtxt<'_>,
+    trait_def_id: DefId,
+    trait_str: &str,
+    err: &mut Diag<'_>,
+) {
     let impls_of = tcx.trait_impls_of(trait_def_id);
-    let impls = if impls_of.blanket_impls().is_empty() {
-        impls_of
-            .non_blanket_impls()
-            .values()
-            .flatten()
-            .filter(|def_id| {
-                !matches!(tcx.type_of(*def_id).instantiate_identity().kind(), ty::Dynamic(..))
-            })
-            .collect::<Vec<_>>()
-    } else {
-        vec![]
-    };
-    let externally_visible = if !impls.is_empty()
-        && let Some(def_id) = trait_def_id.as_local()
+
+    if !impls_of.blanket_impls().is_empty() {
+        return;
+    }
+
+    let concrete_impls: Option<Vec<Ty<'_>>> = impls_of
+        .non_blanket_impls()
+        .values()
+        .flatten()
+        .map(|impl_id| {
+            // Don't suggest conversion to enum if the impl types have type parameters.
+            // It's unlikely the user wants to define a generic enum.
+            let Some(impl_type) = tcx.type_of(*impl_id).no_bound_vars() else { return None };
+
+            // Obviously unsized impl types won't be usable in an enum.
+            // Note: this doesn't use `Ty::is_trivially_sized` because that function
+            // defaults to assuming that things are *not* sized, whereas we want to
+            // fall back to assuming that things may be sized.
+            match impl_type.kind() {
+                ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::DynKind::Dyn) => {
+                    return None;
+                }
+                _ => {}
+            }
+            Some(impl_type)
+        })
+        .collect();
+    let Some(concrete_impls) = concrete_impls else { return };
+
+    const MAX_IMPLS_TO_SUGGEST_CONVERTING_TO_ENUM: usize = 9;
+    if concrete_impls.is_empty() || concrete_impls.len() > MAX_IMPLS_TO_SUGGEST_CONVERTING_TO_ENUM {
+        return;
+    }
+
+    let externally_visible = if let Some(def_id) = trait_def_id.as_local() {
         // We may be executing this during typeck, which would result in cycle
         // if we used effective_visibilities query, which looks into opaque types
         // (and therefore calls typeck).
-        && tcx.resolutions(()).effective_visibilities.is_exported(def_id)
-    {
-        true
+        tcx.resolutions(()).effective_visibilities.is_exported(def_id)
     } else {
         false
     };
-    match &impls[..] {
-        [] => {}
-        _ if impls.len() > 9 => {}
-        [only] if externally_visible => {
-            err.help(with_no_trimmed_paths!(format!(
-                "only type `{}` is seen to implement the trait in this crate, consider using it \
-                 directly instead",
-                tcx.type_of(*only).instantiate_identity(),
-            )));
-        }
-        [only] => {
-            err.help(with_no_trimmed_paths!(format!(
-                "only type `{}` implements the trait, consider using it directly instead",
-                tcx.type_of(*only).instantiate_identity(),
-            )));
-        }
-        impls => {
-            let types = impls
-                .iter()
-                .map(|t| {
-                    with_no_trimmed_paths!(format!("  {}", tcx.type_of(*t).instantiate_identity(),))
-                })
-                .collect::<Vec<_>>();
-            err.help(format!(
-                "the following types implement the trait, consider defining an enum where each \
-                 variant holds one of these types, implementing `{}` for this new enum and using \
-                 it instead:\n{}",
-                trait_str,
-                types.join("\n"),
-            ));
-        }
+
+    if let [only_impl] = &concrete_impls[..] {
+        let within = if externally_visible { " within this crate" } else { "" };
+        err.help(with_no_trimmed_paths!(format!(
+            "only type `{only_impl}` implements `{trait_str}`{within}; \
+            consider using it directly instead."
+        )));
+    } else {
+        let types = concrete_impls
+            .iter()
+            .map(|t| with_no_trimmed_paths!(format!("  {}", t)))
+            .collect::<Vec<String>>()
+            .join("\n");
+
+        err.help(format!(
+            "the following types implement `{trait_str}`:\n\
+             {types}\n\
+             consider defining an enum where each variant holds one of these types,\n\
+             implementing `{trait_str}` for this new enum and using it instead",
+        ));
     }
+
     if externally_visible {
         err.note(format!(
-            "`{trait_str}` can be implemented in other crates; if you want to support your users \
+            "`{trait_str}` may be implemented in other crates; if you want to support your users \
              passing their own types here, you can't refer to a specific type",
         ));
     }
+}
 
-    err
+/// Attempt to suggest that a `dyn Trait` argument or return type be converted
+/// to use `impl Trait`.
+fn attempt_dyn_to_impl_suggestion(tcx: TyCtxt<'_>, hir_id: Option<hir::HirId>, err: &mut Diag<'_>) {
+    let Some(hir_id) = hir_id else { return };
+    let hir::Node::Ty(ty) = tcx.hir_node(hir_id) else { return };
+    let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind else { return };
+
+    // Only suggest converting `dyn` to `impl` if we're in a function signature.
+    // This ensures that we don't suggest converting e.g.
+    //   `type Alias = Box<dyn DynIncompatibleTrait>;` to
+    //   `type Alias = Box<impl DynIncompatibleTrait>;`
+    let Some((_id, first_non_type_parent_node)) =
+        tcx.hir().parent_iter(hir_id).find(|(_id, node)| !matches!(node, hir::Node::Ty(_)))
+    else {
+        return;
+    };
+    if first_non_type_parent_node.fn_sig().is_none() {
+        return;
+    }
+
+    err.span_suggestion_verbose(
+        ty.span.until(trait_ref.span),
+        "consider using an opaque type instead",
+        "impl ",
+        Applicability::MaybeIncorrect,
+    );
 }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
index 2d248d00066..2d932e36470 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
@@ -10,7 +10,7 @@ use rustc_hir::{AttrArgs, AttrKind, Attribute};
 use rustc_macros::LintDiagnostic;
 use rustc_middle::bug;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
-use rustc_middle::ty::{self, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, TyCtxt};
+use rustc_middle::ty::{self, GenericArgsRef, GenericParamDefKind, TyCtxt};
 use rustc_parse_format::{ParseMode, Parser, Piece, Position};
 use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
 use rustc_span::{Span, Symbol, kw, sym};
@@ -42,18 +42,18 @@ static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[
 impl<'tcx> TypeErrCtxt<'_, 'tcx> {
     fn impl_similar_to(
         &self,
-        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
         obligation: &PredicateObligation<'tcx>,
     ) -> Option<(DefId, GenericArgsRef<'tcx>)> {
         let tcx = self.tcx;
         let param_env = obligation.param_env;
-        self.enter_forall(trait_ref, |trait_ref| {
-            let trait_self_ty = trait_ref.self_ty();
+        self.enter_forall(trait_pred, |trait_pred| {
+            let trait_self_ty = trait_pred.self_ty();
 
             let mut self_match_impls = vec![];
             let mut fuzzy_match_impls = vec![];
 
-            self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| {
+            self.tcx.for_each_relevant_impl(trait_pred.def_id(), trait_self_ty, |def_id| {
                 let impl_args = self.fresh_args_for_item(obligation.cause.span, def_id);
                 let impl_trait_ref =
                     tcx.impl_trait_ref(def_id).unwrap().instantiate(tcx, impl_args);
@@ -64,7 +64,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     self_match_impls.push((def_id, impl_args));
 
                     if iter::zip(
-                        trait_ref.args.types().skip(1),
+                        trait_pred.trait_ref.args.types().skip(1),
                         impl_trait_ref.args.types().skip(1),
                     )
                     .all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some())
@@ -117,7 +117,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         }
 
         let (def_id, args) = self
-            .impl_similar_to(trait_pred.to_poly_trait_ref(), obligation)
+            .impl_similar_to(trait_pred, obligation)
             .unwrap_or_else(|| (trait_pred.def_id(), trait_pred.skip_binder().trait_ref.args));
         let trait_pred = trait_pred.skip_binder();
 
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 9d85ca1dd4d..4669d286665 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -32,9 +32,9 @@ use rustc_middle::ty::print::{
     with_forced_trimmed_paths, with_no_trimmed_paths,
 };
 use rustc_middle::ty::{
-    self, AdtKind, GenericArgs, InferTy, IsSuggestable, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable,
-    TypeFolder, TypeSuperFoldable, TypeVisitableExt, TypeckResults, Upcast,
-    suggest_arbitrary_trait_bound, suggest_constraining_type_param,
+    self, AdtKind, GenericArgs, InferTy, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeFolder,
+    TypeSuperFoldable, TypeVisitableExt, TypeckResults, Upcast, suggest_arbitrary_trait_bound,
+    suggest_constraining_type_param,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::LocalDefId;
@@ -218,15 +218,15 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>(
             (_, None) => predicate_constraint(hir_generics, trait_pred.upcast(tcx)),
             (None, Some((ident, []))) => (
                 ident.span.shrink_to_hi(),
-                format!(": {}", trait_pred.to_poly_trait_ref().print_trait_sugared()),
+                format!(": {}", trait_pred.print_modifiers_and_trait_path()),
             ),
             (_, Some((_, [.., bounds]))) => (
                 bounds.span().shrink_to_hi(),
-                format!(" + {}", trait_pred.to_poly_trait_ref().print_trait_sugared()),
+                format!(" + {}", trait_pred.print_modifiers_and_trait_path()),
             ),
             (Some(_), Some((_, []))) => (
                 hir_generics.span.shrink_to_hi(),
-                format!(": {}", trait_pred.to_poly_trait_ref().print_trait_sugared()),
+                format!(": {}", trait_pred.print_modifiers_and_trait_path()),
             ),
         };
 
@@ -2740,7 +2740,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             | ObligationCauseCode::IfExpression { .. }
             | ObligationCauseCode::IfExpressionWithNoElse
             | ObligationCauseCode::MainFunctionType
-            | ObligationCauseCode::StartFunctionType
             | ObligationCauseCode::LangFunctionType(_)
             | ObligationCauseCode::IntrinsicType
             | ObligationCauseCode::MethodReceiver
@@ -3729,7 +3728,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut Diag<'_>,
-        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) {
         let rhs_span = match obligation.cause.code() {
             ObligationCauseCode::BinOp { rhs_span: Some(span), rhs_is_lit, .. } if *rhs_is_lit => {
@@ -3737,8 +3736,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }
             _ => return,
         };
-        if let ty::Float(_) = trait_ref.skip_binder().self_ty().kind()
-            && let ty::Infer(InferTy::IntVar(_)) = trait_ref.skip_binder().args.type_at(1).kind()
+        if let ty::Float(_) = trait_pred.skip_binder().self_ty().kind()
+            && let ty::Infer(InferTy::IntVar(_)) =
+                trait_pred.skip_binder().trait_ref.args.type_at(1).kind()
         {
             err.span_suggestion_verbose(
                 rhs_span.shrink_to_hi(),
@@ -4448,7 +4448,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         &self,
         err: &mut Diag<'_>,
         obligation: &PredicateObligation<'tcx>,
-        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
         candidate_impls: &[ImplCandidate<'tcx>],
         span: Span,
     ) {
@@ -4464,7 +4464,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         // 1. `[T; _]` (array of T)
         // 2. `&[T; _]` (reference to array of T)
         // 3. `&mut [T; _]` (mutable reference to array of T)
-        let (element_ty, mut mutability) = match *trait_ref.skip_binder().self_ty().kind() {
+        let (element_ty, mut mutability) = match *trait_pred.skip_binder().self_ty().kind() {
             ty::Array(element_ty, _) => (element_ty, None),
 
             ty::Ref(_, pointee_ty, mutability) => match *pointee_ty.kind() {
@@ -4620,14 +4620,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     pub(super) fn suggest_desugaring_async_fn_in_trait(
         &self,
         err: &mut Diag<'_>,
-        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) {
         // Don't suggest if RTN is active -- we should prefer a where-clause bound instead.
         if self.tcx.features().return_type_notation() {
             return;
         }
 
-        let trait_def_id = trait_ref.def_id();
+        let trait_def_id = trait_pred.def_id();
 
         // Only suggest specifying auto traits
         if !self.tcx.trait_is_auto(trait_def_id) {
@@ -4635,7 +4635,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
 
         // Look for an RPITIT
-        let ty::Alias(ty::Projection, alias_ty) = trait_ref.self_ty().skip_binder().kind() else {
+        let ty::Alias(ty::Projection, alias_ty) = trait_pred.self_ty().skip_binder().kind() else {
             return;
         };
         let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id }) =
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 53a4e5031c6..0bf91ad35c1 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -1695,13 +1695,6 @@ pub enum ObligationCauseFailureCode {
         #[primary_span]
         span: Span,
     },
-    #[diag(trait_selection_oc_fn_start_correct_type, code = E0308)]
-    FnStartCorrectType {
-        #[primary_span]
-        span: Span,
-        #[subdiagnostic]
-        subdiags: Vec<TypeErrorAdditionalDiags>,
-    },
     #[diag(trait_selection_oc_fn_lang_correct_type, code = E0308)]
     FnLangCorrectType {
         #[primary_span]
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 4498beff4ea..2b7da4bc5ff 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -513,8 +513,27 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
             _ => ChildMode::PassThrough,
         };
 
+        let nested_goals = candidate.instantiate_nested_goals(self.span());
+
+        // If the candidate requires some `T: FnPtr` bound which does not hold should not be treated as
+        // an actual candidate, instead we should treat them as if the impl was never considered to
+        // have potentially applied. As if `impl<A, R> Trait for for<..> fn(..A) -> R` was written
+        // instead of `impl<T: FnPtr> Trait for T`.
+        //
+        // We do this as a separate loop so that we do not choose to tell the user about some nested
+        // goal before we encounter a `T: FnPtr` nested goal.
+        for nested_goal in &nested_goals {
+            if let Some(fn_ptr_trait) = tcx.lang_items().fn_ptr_trait()
+                && let Some(poly_trait_pred) = nested_goal.goal().predicate.as_trait_clause()
+                && poly_trait_pred.def_id() == fn_ptr_trait
+                && let Err(NoSolution) = nested_goal.result()
+            {
+                return ControlFlow::Break(self.obligation.clone());
+            }
+        }
+
         let mut impl_where_bound_count = 0;
-        for nested_goal in candidate.instantiate_nested_goals(self.span()) {
+        for nested_goal in nested_goals {
             trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result()));
 
             let make_obligation = |cause| Obligation {
@@ -605,7 +624,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
     }
 }
 
-#[derive(Copy, Clone)]
+#[derive(Debug, Copy, Clone)]
 enum ChildMode<'tcx> {
     // Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`,
     // and skip all `GoalSource::Misc`, which represent useless obligations
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index e27143f1396..50d47d20e1a 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -709,7 +709,7 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
             if matches!(ty.kind(), ty::Alias(..)) {
                 let ocx = ObligationCtxt::new(infcx);
                 ty = ocx
-                    .structurally_normalize(&ObligationCause::dummy(), param_env, ty)
+                    .structurally_normalize_ty(&ObligationCause::dummy(), param_env, ty)
                     .map_err(|_| ())?;
                 if !ocx.select_where_possible().is_empty() {
                     return Err(());
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index d2abd881c45..66491d9abe1 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -19,6 +19,7 @@ use rustc_middle::ty::{
     TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
 };
 use rustc_span::Span;
+use rustc_type_ir::elaborate;
 use smallvec::SmallVec;
 use tracing::{debug, instrument};
 
@@ -39,7 +40,7 @@ pub fn hir_ty_lowering_dyn_compatibility_violations(
     trait_def_id: DefId,
 ) -> Vec<DynCompatibilityViolation> {
     debug_assert!(tcx.generics_of(trait_def_id).has_self);
-    tcx.supertrait_def_ids(trait_def_id)
+    elaborate::supertrait_def_ids(tcx, trait_def_id)
         .map(|def_id| predicates_reference_self(tcx, def_id, true))
         .filter(|spans| !spans.is_empty())
         .map(DynCompatibilityViolation::SupertraitSelf)
@@ -52,9 +53,8 @@ fn dyn_compatibility_violations(
 ) -> &'_ [DynCompatibilityViolation] {
     debug_assert!(tcx.generics_of(trait_def_id).has_self);
     debug!("dyn_compatibility_violations: {:?}", trait_def_id);
-
     tcx.arena.alloc_from_iter(
-        tcx.supertrait_def_ids(trait_def_id)
+        elaborate::supertrait_def_ids(tcx, trait_def_id)
             .flat_map(|def_id| dyn_compatibility_violations_for_trait(tcx, def_id)),
     )
 }
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index 5e270b62b00..4a3983fca31 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -319,7 +319,7 @@ where
         self.infcx.at(cause, param_env).deeply_normalize(value, &mut **self.engine.borrow_mut())
     }
 
-    pub fn structurally_normalize(
+    pub fn structurally_normalize_ty(
         &self,
         cause: &ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
@@ -327,7 +327,7 @@ where
     ) -> Result<Ty<'tcx>, Vec<E>> {
         self.infcx
             .at(cause, param_env)
-            .structurally_normalize(value, &mut **self.engine.borrow_mut())
+            .structurally_normalize_ty(value, &mut **self.engine.borrow_mut())
     }
 
     pub fn structurally_normalize_const(
@@ -340,4 +340,15 @@ where
             .at(cause, param_env)
             .structurally_normalize_const(value, &mut **self.engine.borrow_mut())
     }
+
+    pub fn structurally_normalize_term(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        value: ty::Term<'tcx>,
+    ) -> Result<ty::Term<'tcx>, Vec<E>> {
+        self.infcx
+            .at(cause, param_env)
+            .structurally_normalize_term(value, &mut **self.engine.borrow_mut())
+    }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index da16a742099..fe5ad003a7e 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -66,9 +66,9 @@ pub use self::specialize::{
 };
 pub use self::structural_normalize::StructurallyNormalizeExt;
 pub use self::util::{
-    BoundVarReplacer, PlaceholderReplacer, TraitAliasExpander, TraitAliasExpansionInfo, elaborate,
-    expand_trait_aliases, impl_item_is_final, supertraits,
-    transitive_bounds_that_define_assoc_item, upcast_choices, with_replaced_escaping_bound_vars,
+    BoundVarReplacer, PlaceholderReplacer, elaborate, expand_trait_aliases, impl_item_is_final,
+    supertrait_def_ids, supertraits, transitive_bounds_that_define_assoc_item, upcast_choices,
+    with_replaced_escaping_bound_vars,
 };
 use crate::error_reporting::InferCtxtErrorExt;
 use crate::infer::outlives::env::OutlivesEnvironment;
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index d59cf88875e..537b042bde5 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -18,6 +18,7 @@ use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{self, Term, Ty, TyCtxt, TypingMode, Upcast};
 use rustc_middle::{bug, span_bug};
 use rustc_span::sym;
+use rustc_type_ir::elaborate;
 use thin_vec::thin_vec;
 use tracing::{debug, instrument};
 
@@ -836,8 +837,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
     if tcx.is_impl_trait_in_trait(obligation.predicate.def_id)
         && let Some(out_trait_def_id) = data.principal_def_id()
         && let rpitit_trait_def_id = tcx.parent(obligation.predicate.def_id)
-        && tcx
-            .supertrait_def_ids(out_trait_def_id)
+        && elaborate::supertrait_def_ids(tcx, out_trait_def_id)
             .any(|trait_def_id| trait_def_id == rpitit_trait_def_id)
     {
         candidate_set.push_candidate(ProjectionCandidate::ObjectRpitit);
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 968dc631e50..13a6744c2e9 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -16,9 +16,9 @@ use rustc_infer::traits::{
     Obligation, ObligationCause, PolyTraitObligation, PredicateObligations, SelectionError,
 };
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
-use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt, TypingMode};
+use rustc_middle::ty::{self, Ty, TypeVisitableExt, TypingMode};
 use rustc_middle::{bug, span_bug};
-use rustc_type_ir::Interner;
+use rustc_type_ir::{Interner, elaborate};
 use tracing::{debug, instrument, trace};
 
 use super::SelectionCandidate::*;
@@ -186,10 +186,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     }
 
                     selcx.infcx.probe(|_| {
+                        // We checked the polarity already
                         match selcx.match_normalize_trait_ref(
                             obligation,
                             placeholder_trait_predicate.trait_ref,
-                            bound.to_poly_trait_ref(),
+                            bound.map_bound(|pred| pred.trait_ref),
                         ) {
                             Ok(None) => {
                                 candidates.vec.push(ProjectionCandidate(idx));
@@ -1002,8 +1003,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     let a_auto_traits: FxIndexSet<DefId> = a_data
                         .auto_traits()
                         .chain(principal_def_id_a.into_iter().flat_map(|principal_def_id| {
-                            self.tcx()
-                                .supertrait_def_ids(principal_def_id)
+                            elaborate::supertrait_def_ids(self.tcx(), principal_def_id)
                                 .filter(|def_id| self.tcx().trait_is_auto(*def_id))
                         }))
                         .collect();
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 0ccb0fc0615..729ae3f2c2a 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -16,7 +16,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::{DefineOpaqueTypes, HigherRankedType, InferOk};
 use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
-use rustc_middle::ty::{self, GenericArgsRef, ToPolyTraitRef, Ty, TyCtxt, Upcast};
+use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, Upcast};
 use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::DefId;
 use rustc_type_ir::elaborate;
@@ -458,8 +458,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         ensure_sufficient_stack(|| {
             let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived);
 
-            let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
-            let trait_ref = self.infcx.enter_forall_and_leak_universe(poly_trait_ref);
+            assert_eq!(obligation.predicate.polarity(), ty::PredicatePolarity::Positive);
+            let trait_ref =
+                self.infcx.enter_forall_and_leak_universe(obligation.predicate).trait_ref;
             let trait_obligations = self.impl_or_trait_obligations(
                 &cause,
                 obligation.recursion_depth + 1,
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 5581ea46882..0cc0d7f786b 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -32,6 +32,7 @@ use rustc_middle::ty::{
     TypingMode, Upcast,
 };
 use rustc_span::{Symbol, sym};
+use rustc_type_ir::elaborate;
 use tracing::{debug, instrument, trace};
 
 use self::EvaluationResult::*;
@@ -2531,7 +2532,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
         let a_auto_traits: FxIndexSet<DefId> = a_data
             .auto_traits()
             .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| {
-                tcx.supertrait_def_ids(principal_def_id).filter(|def_id| tcx.trait_is_auto(*def_id))
+                elaborate::supertrait_def_ids(tcx, principal_def_id)
+                    .filter(|def_id| tcx.trait_is_auto(*def_id))
             }))
             .collect();
 
diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
index f8e8f2176c1..e6d5d336b8d 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
@@ -7,44 +7,12 @@ use crate::traits::{NormalizeExt, Obligation};
 
 #[extension(pub trait StructurallyNormalizeExt<'tcx>)]
 impl<'tcx> At<'_, 'tcx> {
-    fn structurally_normalize<E: 'tcx>(
+    fn structurally_normalize_ty<E: 'tcx>(
         &self,
         ty: Ty<'tcx>,
         fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
     ) -> Result<Ty<'tcx>, Vec<E>> {
-        assert!(!ty.is_ty_var(), "should have resolved vars before calling");
-
-        if self.infcx.next_trait_solver() {
-            let ty::Alias(..) = *ty.kind() else {
-                return Ok(ty);
-            };
-
-            let new_infer_ty = self.infcx.next_ty_var(self.cause.span);
-
-            // We simply emit an `alias-eq` goal here, since that will take care of
-            // normalizing the LHS of the projection until it is a rigid projection
-            // (or a not-yet-defined opaque in scope).
-            let obligation = Obligation::new(
-                self.infcx.tcx,
-                self.cause.clone(),
-                self.param_env,
-                ty::PredicateKind::AliasRelate(
-                    ty.into(),
-                    new_infer_ty.into(),
-                    ty::AliasRelationDirection::Equate,
-                ),
-            );
-
-            fulfill_cx.register_predicate_obligation(self.infcx, obligation);
-            let errors = fulfill_cx.select_where_possible(self.infcx);
-            if !errors.is_empty() {
-                return Err(errors);
-            }
-
-            Ok(self.infcx.resolve_vars_if_possible(new_infer_ty))
-        } else {
-            Ok(self.normalize(ty).into_value_registering_obligations(self.infcx, fulfill_cx))
-        }
+        self.structurally_normalize_term(ty.into(), fulfill_cx).map(|term| term.expect_type())
     }
 
     fn structurally_normalize_const<E: 'tcx>(
@@ -52,14 +20,29 @@ impl<'tcx> At<'_, 'tcx> {
         ct: ty::Const<'tcx>,
         fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
     ) -> Result<ty::Const<'tcx>, Vec<E>> {
-        assert!(!ct.is_ct_infer(), "should have resolved vars before calling");
+        if self.infcx.tcx.features().generic_const_exprs() {
+            return Ok(super::evaluate_const(&self.infcx, ct, self.param_env));
+        }
+
+        self.structurally_normalize_term(ct.into(), fulfill_cx).map(|term| term.expect_const())
+    }
+
+    fn structurally_normalize_term<E: 'tcx>(
+        &self,
+        term: ty::Term<'tcx>,
+        fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
+    ) -> Result<ty::Term<'tcx>, Vec<E>> {
+        assert!(!term.is_infer(), "should have resolved vars before calling");
 
         if self.infcx.next_trait_solver() {
-            let ty::ConstKind::Unevaluated(..) = ct.kind() else {
-                return Ok(ct);
-            };
+            if let None = term.to_alias_term() {
+                return Ok(term);
+            }
 
-            let new_infer_ct = self.infcx.next_const_var(self.cause.span);
+            let new_infer = match term.unpack() {
+                ty::TermKind::Ty(_) => self.infcx.next_ty_var(self.cause.span).into(),
+                ty::TermKind::Const(_) => self.infcx.next_const_var(self.cause.span).into(),
+            };
 
             // We simply emit an `alias-eq` goal here, since that will take care of
             // normalizing the LHS of the projection until it is a rigid projection
@@ -68,11 +51,7 @@ impl<'tcx> At<'_, 'tcx> {
                 self.infcx.tcx,
                 self.cause.clone(),
                 self.param_env,
-                ty::PredicateKind::AliasRelate(
-                    ct.into(),
-                    new_infer_ct.into(),
-                    ty::AliasRelationDirection::Equate,
-                ),
+                ty::PredicateKind::AliasRelate(term, new_infer, ty::AliasRelationDirection::Equate),
             );
 
             fulfill_cx.register_predicate_obligation(self.infcx, obligation);
@@ -81,11 +60,9 @@ impl<'tcx> At<'_, 'tcx> {
                 return Err(errors);
             }
 
-            Ok(self.infcx.resolve_vars_if_possible(new_infer_ct))
-        } else if self.infcx.tcx.features().generic_const_exprs() {
-            Ok(super::evaluate_const(&self.infcx, ct, self.param_env))
+            Ok(self.infcx.resolve_vars_if_possible(new_infer))
         } else {
-            Ok(self.normalize(ct).into_value_registering_obligations(self.infcx, fulfill_cx))
+            Ok(self.normalize(term).into_value_registering_obligations(self.infcx, fulfill_cx))
         }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index da1045b664a..c9fb2a757e1 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -1,162 +1,85 @@
-use std::collections::BTreeMap;
+use std::collections::{BTreeMap, VecDeque};
 
-use rustc_data_structures::fx::FxIndexMap;
-use rustc_errors::Diag;
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::InferCtxt;
 pub use rustc_infer::traits::util::*;
 use rustc_middle::bug;
 use rustc_middle::ty::{
-    self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, Upcast,
+    self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
 };
 use rustc_span::Span;
 use smallvec::{SmallVec, smallvec};
 use tracing::debug;
 
-///////////////////////////////////////////////////////////////////////////
-// `TraitAliasExpander` iterator
-///////////////////////////////////////////////////////////////////////////
-
-/// "Trait alias expansion" is the process of expanding a sequence of trait
-/// references into another sequence by transitively following all trait
-/// aliases. e.g. If you have bounds like `Foo + Send`, a trait alias
-/// `trait Foo = Bar + Sync;`, and another trait alias
-/// `trait Bar = Read + Write`, then the bounds would expand to
-/// `Read + Write + Sync + Send`.
-/// Expansion is done via a DFS (depth-first search), and the `visited` field
-/// is used to avoid cycles.
-pub struct TraitAliasExpander<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    stack: Vec<TraitAliasExpansionInfo<'tcx>>,
-}
-
-/// Stores information about the expansion of a trait via a path of zero or more trait aliases.
-#[derive(Debug, Clone)]
-pub struct TraitAliasExpansionInfo<'tcx> {
-    pub path: SmallVec<[(ty::PolyTraitRef<'tcx>, Span); 4]>,
-}
-
-impl<'tcx> TraitAliasExpansionInfo<'tcx> {
-    fn new(trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self {
-        Self { path: smallvec![(trait_ref, span)] }
-    }
-
-    /// Adds diagnostic labels to `diag` for the expansion path of a trait through all intermediate
-    /// trait aliases.
-    pub fn label_with_exp_info(
-        &self,
-        diag: &mut Diag<'_>,
-        top_label: &'static str,
-        use_desc: &str,
-    ) {
-        diag.span_label(self.top().1, top_label);
-        if self.path.len() > 1 {
-            for (_, sp) in self.path.iter().rev().skip(1).take(self.path.len() - 2) {
-                diag.span_label(*sp, format!("referenced here ({use_desc})"));
-            }
-        }
-        if self.top().1 != self.bottom().1 {
-            // When the trait object is in a return type these two spans match, we don't want
-            // redundant labels.
-            diag.span_label(
-                self.bottom().1,
-                format!("trait alias used in trait object type ({use_desc})"),
-            );
-        }
-    }
-
-    pub fn trait_ref(&self) -> ty::PolyTraitRef<'tcx> {
-        self.top().0
-    }
-
-    pub fn top(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {
-        self.path.last().unwrap()
-    }
-
-    pub fn bottom(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {
-        self.path.first().unwrap()
-    }
-
-    fn clone_and_push(&self, trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self {
-        let mut path = self.path.clone();
-        path.push((trait_ref, span));
-
-        Self { path }
-    }
-}
-
+/// Return the trait and projection predicates that come from eagerly expanding the
+/// trait aliases in the list of clauses. For each trait predicate, record a stack
+/// of spans that trace from the user-written trait alias bound. For projection predicates,
+/// just record the span of the projection itself.
+///
+/// For trait aliases, we don't deduplicte the predicates, since we currently do not
+/// consider duplicated traits as a single trait for the purposes of our "one trait principal"
+/// restriction; however, for projections we do deduplicate them.
+///
+/// ```rust,ignore (fails)
+/// trait Bar {}
+/// trait Foo = Bar + Bar;
+///
+/// let not_object_safe: dyn Foo; // bad, two `Bar` principals.
+/// ```
 pub fn expand_trait_aliases<'tcx>(
     tcx: TyCtxt<'tcx>,
-    trait_refs: impl Iterator<Item = (ty::PolyTraitRef<'tcx>, Span)>,
-) -> TraitAliasExpander<'tcx> {
-    let items: Vec<_> =
-        trait_refs.map(|(trait_ref, span)| TraitAliasExpansionInfo::new(trait_ref, span)).collect();
-    TraitAliasExpander { tcx, stack: items }
-}
-
-impl<'tcx> TraitAliasExpander<'tcx> {
-    /// If `item` is a trait alias and its predicate has not yet been visited, then expands `item`
-    /// to the definition, pushes the resulting expansion onto `self.stack`, and returns `false`.
-    /// Otherwise, immediately returns `true` if `item` is a regular trait, or `false` if it is a
-    /// trait alias.
-    /// The return value indicates whether `item` should be yielded to the user.
-    fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool {
-        let tcx = self.tcx;
-        let trait_ref = item.trait_ref();
-        let pred = trait_ref.upcast(tcx);
-
-        debug!("expand_trait_aliases: trait_ref={:?}", trait_ref);
-
-        // Don't recurse if this bound is not a trait alias.
-        let is_alias = tcx.is_trait_alias(trait_ref.def_id());
-        if !is_alias {
-            return true;
-        }
-
-        // Don't recurse if this trait alias is already on the stack for the DFS search.
-        let anon_pred = anonymize_predicate(tcx, pred);
-        if item
-            .path
-            .iter()
-            .rev()
-            .skip(1)
-            .any(|&(tr, _)| anonymize_predicate(tcx, tr.upcast(tcx)) == anon_pred)
-        {
-            return false;
-        }
-
-        // Get components of trait alias.
-        let predicates = tcx.explicit_super_predicates_of(trait_ref.def_id());
-        debug!(?predicates);
-
-        let items = predicates.skip_binder().iter().rev().filter_map(|(pred, span)| {
-            pred.instantiate_supertrait(tcx, trait_ref)
-                .as_trait_clause()
-                .map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span))
-        });
-        debug!("expand_trait_aliases: items={:?}", items.clone().collect::<Vec<_>>());
-
-        self.stack.extend(items);
-
-        false
-    }
-}
-
-impl<'tcx> Iterator for TraitAliasExpander<'tcx> {
-    type Item = TraitAliasExpansionInfo<'tcx>;
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        (self.stack.len(), None)
-    }
-
-    fn next(&mut self) -> Option<TraitAliasExpansionInfo<'tcx>> {
-        while let Some(item) = self.stack.pop() {
-            if self.expand(&item) {
-                return Some(item);
+    clauses: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
+) -> (
+    Vec<(ty::PolyTraitPredicate<'tcx>, SmallVec<[Span; 1]>)>,
+    Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,
+) {
+    let mut trait_preds = vec![];
+    let mut projection_preds = vec![];
+    let mut seen_projection_preds = FxHashSet::default();
+
+    let mut queue: VecDeque<_> = clauses.into_iter().map(|(p, s)| (p, smallvec![s])).collect();
+
+    while let Some((clause, spans)) = queue.pop_front() {
+        match clause.kind().skip_binder() {
+            ty::ClauseKind::Trait(trait_pred) => {
+                if tcx.is_trait_alias(trait_pred.def_id()) {
+                    queue.extend(
+                        tcx.explicit_super_predicates_of(trait_pred.def_id())
+                            .iter_identity_copied()
+                            .map(|(clause, span)| {
+                                let mut spans = spans.clone();
+                                spans.push(span);
+                                (
+                                    clause.instantiate_supertrait(
+                                        tcx,
+                                        clause.kind().rebind(trait_pred.trait_ref),
+                                    ),
+                                    spans,
+                                )
+                            }),
+                    );
+                } else {
+                    trait_preds.push((clause.kind().rebind(trait_pred), spans));
+                }
             }
+            ty::ClauseKind::Projection(projection_pred) => {
+                let projection_pred = clause.kind().rebind(projection_pred);
+                if !seen_projection_preds.insert(tcx.anonymize_bound_vars(projection_pred)) {
+                    continue;
+                }
+                projection_preds.push((projection_pred, *spans.last().unwrap()));
+            }
+            ty::ClauseKind::RegionOutlives(..)
+            | ty::ClauseKind::TypeOutlives(..)
+            | ty::ClauseKind::ConstArgHasType(_, _)
+            | ty::ClauseKind::WellFormed(_)
+            | ty::ClauseKind::ConstEvaluatable(_)
+            | ty::ClauseKind::HostEffect(..) => {}
         }
-        None
     }
+
+    (trait_preds, projection_preds)
 }
 
 ///////////////////////////////////////////////////////////////////////////
diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs
index 71c3646498b..3213638afb2 100644
--- a/compiler/rustc_type_ir/src/visit.rs
+++ b/compiler/rustc_type_ir/src/visit.rs
@@ -47,6 +47,7 @@ use std::ops::ControlFlow;
 use rustc_ast_ir::visit::VisitorResult;
 use rustc_ast_ir::{try_visit, walk_visitable_list};
 use rustc_index::{Idx, IndexVec};
+use smallvec::SmallVec;
 use thin_vec::ThinVec;
 
 use crate::data_structures::Lrc;
@@ -192,6 +193,13 @@ impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for ThinVec<T> {
     }
 }
 
+impl<I: Interner, T: TypeVisitable<I>, const N: usize> TypeVisitable<I> for SmallVec<[T; N]> {
+    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
+        walk_visitable_list!(visitor, self.iter());
+        V::Result::output()
+    }
+}
+
 // `TypeFoldable` isn't impl'd for `&[T]`. It doesn't make sense in the general
 // case, because we can't return a new slice. But note that there are a couple
 // of trivial impls of `TypeFoldable` for specific slice types elsewhere.
diff --git a/library/Cargo.lock b/library/Cargo.lock
index c8007dd9be0..7b9081d46a0 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -166,9 +166,9 @@ dependencies = [
 
 [[package]]
 name = "miniz_oxide"
-version = "0.8.2"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394"
+checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924"
 dependencies = [
  "adler2",
  "compiler_builtins",
diff --git a/library/alloc/src/bstr.rs b/library/alloc/src/bstr.rs
new file mode 100644
index 00000000000..61e61019b50
--- /dev/null
+++ b/library/alloc/src/bstr.rs
@@ -0,0 +1,702 @@
+//! The `ByteStr` and `ByteString` types and trait implementations.
+
+// This could be more fine-grained.
+#![cfg(not(no_global_oom_handling))]
+
+use core::borrow::{Borrow, BorrowMut};
+#[unstable(feature = "bstr", issue = "134915")]
+pub use core::bstr::ByteStr;
+use core::bstr::{impl_partial_eq, impl_partial_eq_n, impl_partial_eq_ord};
+use core::cmp::Ordering;
+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;
+use crate::string::String;
+#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))]
+use crate::sync::Arc;
+use crate::vec::Vec;
+
+/// A wrapper for `Vec<u8>` representing a human-readable string that's conventionally, but not
+/// always, UTF-8.
+///
+/// Unlike `String`, this type permits non-UTF-8 contents, making it suitable for user input,
+/// non-native filenames (as `Path` only supports native filenames), and other applications that
+/// need to round-trip whatever data the user provides.
+///
+/// A `ByteString` owns its contents and can grow and shrink, like a `Vec` or `String`. For a
+/// borrowed byte string, see [`ByteStr`](../../std/bstr/struct.ByteStr.html).
+///
+/// `ByteString` implements `Deref` to `&Vec<u8>`, so all methods available on `&Vec<u8>` are
+/// available on `ByteString`. Similarly, `ByteString` implements `DerefMut` to `&mut Vec<u8>`,
+/// so you can modify a `ByteString` using any method available on `&mut Vec<u8>`.
+///
+/// The `Debug` and `Display` implementations for `ByteString` are the same as those for `ByteStr`,
+/// showing invalid UTF-8 as hex escapes or the Unicode replacement character, respectively.
+#[unstable(feature = "bstr", issue = "134915")]
+#[repr(transparent)]
+#[derive(Clone)]
+#[doc(alias = "BString")]
+pub struct ByteString(pub Vec<u8>);
+
+impl ByteString {
+    #[inline]
+    pub(crate) fn as_bytes(&self) -> &[u8] {
+        &self.0
+    }
+
+    #[inline]
+    pub(crate) fn as_bytestr(&self) -> &ByteStr {
+        ByteStr::new(&self.0)
+    }
+
+    #[inline]
+    pub(crate) fn as_mut_bytestr(&mut self) -> &mut ByteStr {
+        ByteStr::from_bytes_mut(&mut self.0)
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Deref for ByteString {
+    type Target = Vec<u8>;
+
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl DerefMut for ByteString {
+    #[inline]
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+#[unstable(feature = "deref_pure_trait", issue = "87121")]
+unsafe impl DerefPure for ByteString {}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl fmt::Debug for ByteString {
+    #[inline]
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Debug::fmt(self.as_bytestr(), f)
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl fmt::Display for ByteString {
+    #[inline]
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self.as_bytestr(), f)
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl AsRef<[u8]> for ByteString {
+    #[inline]
+    fn as_ref(&self) -> &[u8] {
+        &self.0
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl AsRef<ByteStr> for ByteString {
+    #[inline]
+    fn as_ref(&self) -> &ByteStr {
+        self.as_bytestr()
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl AsMut<[u8]> for ByteString {
+    #[inline]
+    fn as_mut(&mut self) -> &mut [u8] {
+        &mut self.0
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl AsMut<ByteStr> for ByteString {
+    #[inline]
+    fn as_mut(&mut self) -> &mut ByteStr {
+        self.as_mut_bytestr()
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Borrow<[u8]> for ByteString {
+    #[inline]
+    fn borrow(&self) -> &[u8] {
+        &self.0
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Borrow<ByteStr> for ByteString {
+    #[inline]
+    fn borrow(&self) -> &ByteStr {
+        self.as_bytestr()
+    }
+}
+
+// `impl Borrow<ByteStr> for Vec<u8>` omitted to avoid inference failures
+// `impl Borrow<ByteStr> for String` omitted to avoid inference failures
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl BorrowMut<[u8]> for ByteString {
+    #[inline]
+    fn borrow_mut(&mut self) -> &mut [u8] {
+        &mut self.0
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl BorrowMut<ByteStr> for ByteString {
+    #[inline]
+    fn borrow_mut(&mut self) -> &mut ByteStr {
+        self.as_mut_bytestr()
+    }
+}
+
+// `impl BorrowMut<ByteStr> for Vec<u8>` omitted to avoid inference failures
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Default for ByteString {
+    fn default() -> Self {
+        ByteString(Vec::new())
+    }
+}
+
+// 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]
+//     fn from(s: &'a [u8; N]) -> Self {
+//         ByteString(s.as_slice().to_vec())
+//     }
+// }
+//
+// #[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]
+//     fn from(s: [u8; N]) -> Self {
+//         ByteString(s.as_slice().to_vec())
+//     }
+// }
+//
+// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+// #[unstable(feature = "bstr", issue = "134915")]
+// impl<'a> From<&'a [u8]> for ByteString {
+//     #[inline]
+//     fn from(s: &'a [u8]) -> Self {
+//         ByteString(s.to_vec())
+//     }
+// }
+//
+// #[unstable(feature = "bstr", issue = "134915")]
+// impl From<Vec<u8>> for ByteString {
+//     #[inline]
+//     fn from(s: Vec<u8>) -> Self {
+//         ByteString(s)
+//     }
+// }
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl From<ByteString> for Vec<u8> {
+    #[inline]
+    fn from(s: ByteString) -> Self {
+        s.0
+    }
+}
+
+// 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]
+//     fn from(s: &'a str) -> Self {
+//         ByteString(s.as_bytes().to_vec())
+//     }
+// }
+//
+// #[unstable(feature = "bstr", issue = "134915")]
+// impl From<String> for ByteString {
+//     #[inline]
+//     fn from(s: String) -> Self {
+//         ByteString(s.into_bytes())
+//     }
+// }
+
+#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+#[unstable(feature = "bstr", issue = "134915")]
+impl<'a> From<&'a ByteStr> for ByteString {
+    #[inline]
+    fn from(s: &'a ByteStr) -> Self {
+        ByteString(s.0.to_vec())
+    }
+}
+
+#[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]
+    fn from(s: ByteString) -> Self {
+        Cow::Owned(s)
+    }
+}
+
+#[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]
+    fn from(s: &'a ByteString) -> Self {
+        Cow::Borrowed(s.as_bytestr())
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl FromIterator<char> for ByteString {
+    #[inline]
+    fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
+        ByteString(iter.into_iter().collect::<String>().into_bytes())
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl FromIterator<u8> for ByteString {
+    #[inline]
+    fn from_iter<T: IntoIterator<Item = u8>>(iter: T) -> Self {
+        ByteString(iter.into_iter().collect())
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl<'a> FromIterator<&'a str> for ByteString {
+    #[inline]
+    fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
+        ByteString(iter.into_iter().collect::<String>().into_bytes())
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl<'a> FromIterator<&'a [u8]> for ByteString {
+    #[inline]
+    fn from_iter<T: IntoIterator<Item = &'a [u8]>>(iter: T) -> Self {
+        let mut buf = Vec::new();
+        for b in iter {
+            buf.extend_from_slice(b);
+        }
+        ByteString(buf)
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl<'a> FromIterator<&'a ByteStr> for ByteString {
+    #[inline]
+    fn from_iter<T: IntoIterator<Item = &'a ByteStr>>(iter: T) -> Self {
+        let mut buf = Vec::new();
+        for b in iter {
+            buf.extend_from_slice(&b.0);
+        }
+        ByteString(buf)
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl FromIterator<ByteString> for ByteString {
+    #[inline]
+    fn from_iter<T: IntoIterator<Item = ByteString>>(iter: T) -> Self {
+        let mut buf = Vec::new();
+        for mut b in iter {
+            buf.append(&mut b.0);
+        }
+        ByteString(buf)
+    }
+}
+
+#[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;
+
+    #[inline]
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        Ok(ByteString(s.as_bytes().to_vec()))
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<usize> for ByteString {
+    type Output = u8;
+
+    #[inline]
+    fn index(&self, idx: usize) -> &u8 {
+        &self.0[idx]
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<RangeFull> for ByteString {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, _: RangeFull) -> &ByteStr {
+        self.as_bytestr()
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<Range<usize>> for ByteString {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, r: Range<usize>) -> &ByteStr {
+        ByteStr::from_bytes(&self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<RangeInclusive<usize>> for ByteString {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, r: RangeInclusive<usize>) -> &ByteStr {
+        ByteStr::from_bytes(&self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<RangeFrom<usize>> for ByteString {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, r: RangeFrom<usize>) -> &ByteStr {
+        ByteStr::from_bytes(&self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<RangeTo<usize>> for ByteString {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, r: RangeTo<usize>) -> &ByteStr {
+        ByteStr::from_bytes(&self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<RangeToInclusive<usize>> for ByteString {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, r: RangeToInclusive<usize>) -> &ByteStr {
+        ByteStr::from_bytes(&self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<usize> for ByteString {
+    #[inline]
+    fn index_mut(&mut self, idx: usize) -> &mut u8 {
+        &mut self.0[idx]
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<RangeFull> for ByteString {
+    #[inline]
+    fn index_mut(&mut self, _: RangeFull) -> &mut ByteStr {
+        self.as_mut_bytestr()
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<Range<usize>> for ByteString {
+    #[inline]
+    fn index_mut(&mut self, r: Range<usize>) -> &mut ByteStr {
+        ByteStr::from_bytes_mut(&mut self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<RangeInclusive<usize>> for ByteString {
+    #[inline]
+    fn index_mut(&mut self, r: RangeInclusive<usize>) -> &mut ByteStr {
+        ByteStr::from_bytes_mut(&mut self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<RangeFrom<usize>> for ByteString {
+    #[inline]
+    fn index_mut(&mut self, r: RangeFrom<usize>) -> &mut ByteStr {
+        ByteStr::from_bytes_mut(&mut self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<RangeTo<usize>> for ByteString {
+    #[inline]
+    fn index_mut(&mut self, r: RangeTo<usize>) -> &mut ByteStr {
+        ByteStr::from_bytes_mut(&mut self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<RangeToInclusive<usize>> for ByteString {
+    #[inline]
+    fn index_mut(&mut self, r: RangeToInclusive<usize>) -> &mut ByteStr {
+        ByteStr::from_bytes_mut(&mut self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl hash::Hash for ByteString {
+    #[inline]
+    fn hash<H: hash::Hasher>(&self, state: &mut H) {
+        self.0.hash(state);
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Eq for ByteString {}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl PartialEq for ByteString {
+    #[inline]
+    fn eq(&self, other: &ByteString) -> bool {
+        self.0 == other.0
+    }
+}
+
+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 {
+            #[inline]
+            fn eq(&self, other: &$rhs) -> bool {
+                let other: &[u8] = (&**other).as_ref();
+                PartialEq::eq(self.as_bytes(), other)
+            }
+        }
+
+        #[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 {
+            #[inline]
+            fn eq(&self, other: &$lhs) -> bool {
+                let this: &[u8] = (&**self).as_ref();
+                PartialEq::eq(this, other.as_bytes())
+            }
+        }
+
+        #[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 {
+            #[inline]
+            fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
+                let other: &[u8] = (&**other).as_ref();
+                PartialOrd::partial_cmp(self.as_bytes(), other)
+            }
+        }
+
+        #[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 {
+            #[inline]
+            fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
+                let this: &[u8] = (&**self).as_ref();
+                PartialOrd::partial_cmp(this, other.as_bytes())
+            }
+        }
+    };
+}
+
+// PartialOrd with `Vec<u8>` omitted to avoid inference failures
+impl_partial_eq!(ByteString, Vec<u8>);
+// PartialOrd with `[u8]` omitted to avoid inference failures
+impl_partial_eq!(ByteString, [u8]);
+// PartialOrd with `&[u8]` omitted to avoid inference failures
+impl_partial_eq!(ByteString, &[u8]);
+// PartialOrd with `String` omitted to avoid inference failures
+impl_partial_eq!(ByteString, String);
+// PartialOrd with `str` omitted to avoid inference failures
+impl_partial_eq!(ByteString, str);
+// PartialOrd with `&str` omitted to avoid inference failures
+impl_partial_eq!(ByteString, &str);
+impl_partial_eq_ord!(ByteString, ByteStr);
+impl_partial_eq_ord!(ByteString, &ByteStr);
+// PartialOrd with `[u8; N]` omitted to avoid inference failures
+impl_partial_eq_n!(ByteString, [u8; N]);
+// PartialOrd with `&[u8; N]` omitted to avoid inference failures
+impl_partial_eq_n!(ByteString, &[u8; N]);
+impl_partial_eq_ord_cow!(ByteString, Cow<'_, ByteStr>);
+impl_partial_eq_ord_cow!(ByteString, Cow<'_, str>);
+impl_partial_eq_ord_cow!(ByteString, Cow<'_, [u8]>);
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Ord for ByteString {
+    #[inline]
+    fn cmp(&self, other: &ByteString) -> Ordering {
+        Ord::cmp(&self.0, &other.0)
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl PartialOrd for ByteString {
+    #[inline]
+    fn partial_cmp(&self, other: &ByteString) -> Option<Ordering> {
+        PartialOrd::partial_cmp(&self.0, &other.0)
+    }
+}
+
+#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+#[unstable(feature = "bstr", issue = "134915")]
+impl ToOwned for ByteStr {
+    type Owned = ByteString;
+
+    #[inline]
+    fn to_owned(&self) -> ByteString {
+        ByteString(self.0.to_vec())
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl TryFrom<ByteString> for String {
+    type Error = crate::string::FromUtf8Error;
+
+    #[inline]
+    fn try_from(s: ByteString) -> Result<Self, Self::Error> {
+        String::from_utf8(s.0)
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl<'a> TryFrom<&'a ByteString> for &'a str {
+    type Error = crate::str::Utf8Error;
+
+    #[inline]
+    fn try_from(s: &'a ByteString) -> Result<Self, Self::Error> {
+        crate::str::from_utf8(s.0.as_slice())
+    }
+}
+
+// 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]
+    fn clone(&self) -> Self {
+        Self::from(Box::<[u8]>::from(&self.0))
+    }
+}
+
+#[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]
+    fn from(s: &'a ByteStr) -> Self {
+        Cow::Borrowed(s)
+    }
+}
+
+#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+#[unstable(feature = "bstr", issue = "134915")]
+impl From<Box<[u8]>> for Box<ByteStr> {
+    #[inline]
+    fn from(s: Box<[u8]>) -> Box<ByteStr> {
+        // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`.
+        unsafe { Box::from_raw(Box::into_raw(s) as _) }
+    }
+}
+
+#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
+#[unstable(feature = "bstr", issue = "134915")]
+impl From<Box<ByteStr>> for Box<[u8]> {
+    #[inline]
+    fn from(s: Box<ByteStr>) -> Box<[u8]> {
+        // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`.
+        unsafe { Box::from_raw(Box::into_raw(s) as _) }
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+#[cfg(not(no_rc))]
+impl From<Rc<[u8]>> for Rc<ByteStr> {
+    #[inline]
+    fn from(s: Rc<[u8]>) -> Rc<ByteStr> {
+        // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`.
+        unsafe { Rc::from_raw(Rc::into_raw(s) as _) }
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+#[cfg(not(no_rc))]
+impl From<Rc<ByteStr>> for Rc<[u8]> {
+    #[inline]
+    fn from(s: Rc<ByteStr>) -> Rc<[u8]> {
+        // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`.
+        unsafe { Rc::from_raw(Rc::into_raw(s) as _) }
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))]
+impl From<Arc<[u8]>> for Arc<ByteStr> {
+    #[inline]
+    fn from(s: Arc<[u8]>) -> Arc<ByteStr> {
+        // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`.
+        unsafe { Arc::from_raw(Arc::into_raw(s) as _) }
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))]
+impl From<Arc<ByteStr>> for Arc<[u8]> {
+    #[inline]
+    fn from(s: Arc<ByteStr>) -> Arc<[u8]> {
+        // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`.
+        unsafe { Arc::from_raw(Arc::into_raw(s) as _) }
+    }
+}
+
+// PartialOrd with `Vec<u8>` omitted to avoid inference failures
+impl_partial_eq!(ByteStr, Vec<u8>);
+// PartialOrd with `String` omitted to avoid inference failures
+impl_partial_eq!(ByteStr, String);
+impl_partial_eq_ord_cow!(&'a ByteStr, Cow<'a, ByteStr>);
+impl_partial_eq_ord_cow!(&'a ByteStr, Cow<'a, str>);
+impl_partial_eq_ord_cow!(&'a ByteStr, Cow<'a, [u8]>);
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl<'a> TryFrom<&'a ByteStr> for String {
+    type Error = core::str::Utf8Error;
+
+    #[inline]
+    fn try_from(s: &'a ByteStr) -> Result<Self, Self::Error> {
+        Ok(core::str::from_utf8(&s.0)?.into())
+    }
+}
diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs
index 9660023d694..041f80c1f2c 100644
--- a/library/alloc/src/collections/btree/set.rs
+++ b/library/alloc/src/collections/btree/set.rs
@@ -1442,20 +1442,20 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
     ///
     /// let mut set = BTreeSet::from([1, 2, 3, 4]);
     ///
-    /// let mut cursor = unsafe { set.upper_bound_mut(Bound::Included(&3)) };
+    /// let mut cursor = set.upper_bound_mut(Bound::Included(&3));
     /// assert_eq!(cursor.peek_prev(), Some(&3));
     /// assert_eq!(cursor.peek_next(), Some(&4));
     ///
-    /// let mut cursor = unsafe { set.upper_bound_mut(Bound::Excluded(&3)) };
+    /// let mut cursor = set.upper_bound_mut(Bound::Excluded(&3));
     /// assert_eq!(cursor.peek_prev(), Some(&2));
     /// assert_eq!(cursor.peek_next(), Some(&3));
     ///
-    /// let mut cursor = unsafe { set.upper_bound_mut(Bound::Unbounded) };
+    /// let mut cursor = set.upper_bound_mut(Bound::Unbounded);
     /// assert_eq!(cursor.peek_prev(), Some(&4));
     /// assert_eq!(cursor.peek_next(), None);
     /// ```
     #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub unsafe fn upper_bound_mut<Q: ?Sized>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, T, A>
+    pub fn upper_bound_mut<Q: ?Sized>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, T, A>
     where
         T: Borrow<Q> + Ord,
         Q: Ord,
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index b4f08debc93..28e4217e303 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -102,6 +102,8 @@
 #![feature(async_fn_traits)]
 #![feature(async_iterator)]
 #![feature(box_uninit_write)]
+#![feature(bstr)]
+#![feature(bstr_internals)]
 #![feature(clone_to_uninit)]
 #![feature(coerce_unsized)]
 #![feature(const_eval_select)]
@@ -228,6 +230,8 @@ mod boxed {
     pub use std::boxed::Box;
 }
 pub mod borrow;
+#[unstable(feature = "bstr", issue = "134915")]
+pub mod bstr;
 pub mod collections;
 #[cfg(all(not(no_rc), not(no_sync), not(no_global_oom_handling)))]
 pub mod ffi;
diff --git a/library/core/src/arch.rs b/library/core/src/arch.rs
index cb130f60cec..81d828a971c 100644
--- a/library/core/src/arch.rs
+++ b/library/core/src/arch.rs
@@ -1,6 +1,14 @@
 #![doc = include_str!("../../stdarch/crates/core_arch/src/core_arch_docs.md")]
 
-#[allow(unused_imports)]
+#[allow(
+    // some targets don't have anything to reexport, which
+    // makes the `pub use` unused and unreachable, allow
+    // both lints as to not have `#[cfg]`s
+    //
+    // cf. https://github.com/rust-lang/rust/pull/116033#issuecomment-1760085575
+    unused_imports,
+    unreachable_pub
+)]
 #[stable(feature = "simd_arch", since = "1.27.0")]
 pub use crate::core_arch::arch::*;
 
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index 2ae5ded1fd5..28329bb0908 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -156,7 +156,6 @@ pub const fn from_mut<T>(s: &mut T) -> &mut [T; 1] {
 
 /// The error type returned when a conversion from a slice to an array fails.
 #[stable(feature = "try_from", since = "1.34.0")]
-#[rustc_allowed_through_unstable_modules]
 #[derive(Debug, Copy, Clone)]
 pub struct TryFromSliceError(());
 
@@ -893,7 +892,7 @@ impl<T> Guard<'_, T> {
     ///
     /// No more than N elements must be initialized.
     #[inline]
-    pub unsafe fn push_unchecked(&mut self, item: T) {
+    pub(crate) unsafe fn push_unchecked(&mut self, item: T) {
         // SAFETY: If `initialized` was correct before and the caller does not
         // invoke this method more than N times then writes will be in-bounds
         // and slots will not be initialized more than once.
diff --git a/library/core/src/bstr.rs b/library/core/src/bstr.rs
new file mode 100644
index 00000000000..74e07f3d242
--- /dev/null
+++ b/library/core/src/bstr.rs
@@ -0,0 +1,581 @@
+//! The `ByteStr` type and trait implementations.
+
+use crate::borrow::{Borrow, BorrowMut};
+use crate::cmp::Ordering;
+use crate::ops::{
+    Deref, DerefMut, DerefPure, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive,
+    RangeTo, RangeToInclusive,
+};
+use crate::{fmt, hash};
+
+/// A wrapper for `&[u8]` representing a human-readable string that's conventionally, but not
+/// always, UTF-8.
+///
+/// Unlike `&str`, this type permits non-UTF-8 contents, making it suitable for user input,
+/// non-native filenames (as `Path` only supports native filenames), and other applications that
+/// need to round-trip whatever data the user provides.
+///
+/// For an owned, growable byte string buffer, use
+/// [`ByteString`](../../std/bstr/struct.ByteString.html).
+///
+/// `ByteStr` implements `Deref` to `[u8]`, so all methods available on `[u8]` are available on
+/// `ByteStr`.
+///
+/// # Representation
+///
+/// A `&ByteStr` has the same representation as a `&str`. That is, a `&ByteStr` is a wide pointer
+/// which includes a pointer to some bytes and a length.
+///
+/// # Trait implementations
+///
+/// The `ByteStr` type has a number of trait implementations, and in particular, defines equality
+/// and comparisons between `&ByteStr`, `&str`, and `&[u8]`, for convenience.
+///
+/// The `Debug` implementation for `ByteStr` shows its bytes as a normal string, with invalid UTF-8
+/// presented as hex escape sequences.
+///
+/// The `Display` implementation behaves as if the `ByteStr` were first lossily converted to a
+/// `str`, with invalid UTF-8 presented as the Unicode replacement character: �
+///
+#[unstable(feature = "bstr", issue = "134915")]
+#[repr(transparent)]
+#[doc(alias = "BStr")]
+pub struct ByteStr(pub [u8]);
+
+impl ByteStr {
+    /// Creates a `ByteStr` slice from anything that can be converted to a byte slice.
+    ///
+    /// This is a zero-cost conversion.
+    ///
+    /// # Example
+    ///
+    /// You can create a `ByteStr` from a byte array, a byte slice or a string slice:
+    ///
+    /// ```
+    /// # #![feature(bstr)]
+    /// # use std::bstr::ByteStr;
+    /// let a = ByteStr::new(b"abc");
+    /// let b = ByteStr::new(&b"abc"[..]);
+    /// let c = ByteStr::new("abc");
+    ///
+    /// assert_eq!(a, b);
+    /// assert_eq!(a, c);
+    /// ```
+    #[inline]
+    #[unstable(feature = "bstr", issue = "134915")]
+    pub fn new<B: ?Sized + AsRef<[u8]>>(bytes: &B) -> &Self {
+        ByteStr::from_bytes(bytes.as_ref())
+    }
+
+    #[doc(hidden)]
+    #[unstable(feature = "bstr_internals", issue = "none")]
+    #[inline]
+    pub fn from_bytes(slice: &[u8]) -> &Self {
+        // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`, so we can turn a reference to
+        // the wrapped type into a reference to the wrapper type.
+        unsafe { &*(slice as *const [u8] as *const Self) }
+    }
+
+    #[doc(hidden)]
+    #[unstable(feature = "bstr_internals", issue = "none")]
+    #[inline]
+    pub fn from_bytes_mut(slice: &mut [u8]) -> &mut Self {
+        // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`, so we can turn a reference to
+        // the wrapped type into a reference to the wrapper type.
+        unsafe { &mut *(slice as *mut [u8] as *mut Self) }
+    }
+
+    #[doc(hidden)]
+    #[unstable(feature = "bstr_internals", issue = "none")]
+    #[inline]
+    pub fn as_bytes(&self) -> &[u8] {
+        &self.0
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Deref for ByteStr {
+    type Target = [u8];
+
+    #[inline]
+    fn deref(&self) -> &[u8] {
+        &self.0
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl DerefMut for ByteStr {
+    #[inline]
+    fn deref_mut(&mut self) -> &mut [u8] {
+        &mut self.0
+    }
+}
+
+#[unstable(feature = "deref_pure_trait", issue = "87121")]
+unsafe impl DerefPure for ByteStr {}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl fmt::Debug for ByteStr {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "\"")?;
+        for chunk in self.utf8_chunks() {
+            for c in chunk.valid().chars() {
+                match c {
+                    '\0' => write!(f, "\\0")?,
+                    '\x01'..='\x7f' => write!(f, "{}", (c as u8).escape_ascii())?,
+                    _ => write!(f, "{}", c.escape_debug())?,
+                }
+            }
+            write!(f, "{}", chunk.invalid().escape_ascii())?;
+        }
+        write!(f, "\"")?;
+        Ok(())
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl fmt::Display for ByteStr {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fn fmt_nopad(this: &ByteStr, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            for chunk in this.utf8_chunks() {
+                f.write_str(chunk.valid())?;
+                if !chunk.invalid().is_empty() {
+                    f.write_str("\u{FFFD}")?;
+                }
+            }
+            Ok(())
+        }
+
+        let Some(align) = f.align() else {
+            return fmt_nopad(self, f);
+        };
+        let nchars: usize = self
+            .utf8_chunks()
+            .map(|chunk| chunk.valid().len() + if chunk.invalid().is_empty() { 0 } else { 1 })
+            .sum();
+        let padding = f.width().unwrap_or(0).saturating_sub(nchars);
+        let fill = f.fill();
+        let (lpad, rpad) = match align {
+            fmt::Alignment::Left => (0, padding),
+            fmt::Alignment::Right => (padding, 0),
+            fmt::Alignment::Center => {
+                let half = padding / 2;
+                (half, half + padding % 2)
+            }
+        };
+        for _ in 0..lpad {
+            write!(f, "{fill}")?;
+        }
+        fmt_nopad(self, f)?;
+        for _ in 0..rpad {
+            write!(f, "{fill}")?;
+        }
+
+        Ok(())
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl AsRef<[u8]> for ByteStr {
+    #[inline]
+    fn as_ref(&self) -> &[u8] {
+        &self.0
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl AsRef<ByteStr> for ByteStr {
+    #[inline]
+    fn as_ref(&self) -> &ByteStr {
+        self
+    }
+}
+
+// `impl AsRef<ByteStr> for [u8]` omitted to avoid widespread inference failures
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl AsRef<ByteStr> for str {
+    #[inline]
+    fn as_ref(&self) -> &ByteStr {
+        ByteStr::new(self)
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl AsMut<[u8]> for ByteStr {
+    #[inline]
+    fn as_mut(&mut self) -> &mut [u8] {
+        &mut self.0
+    }
+}
+
+// `impl AsMut<ByteStr> for [u8]` omitted to avoid widespread inference failures
+
+// `impl Borrow<ByteStr> for [u8]` omitted to avoid widespread inference failures
+
+// `impl Borrow<ByteStr> for str` omitted to avoid widespread inference failures
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Borrow<[u8]> for ByteStr {
+    #[inline]
+    fn borrow(&self) -> &[u8] {
+        &self.0
+    }
+}
+
+// `impl BorrowMut<ByteStr> for [u8]` omitted to avoid widespread inference failures
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl BorrowMut<[u8]> for ByteStr {
+    #[inline]
+    fn borrow_mut(&mut self) -> &mut [u8] {
+        &mut self.0
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl<'a> Default for &'a ByteStr {
+    fn default() -> Self {
+        ByteStr::from_bytes(b"")
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl<'a> Default for &'a mut ByteStr {
+    fn default() -> Self {
+        ByteStr::from_bytes_mut(&mut [])
+    }
+}
+
+// Omitted due to inference failures
+//
+// #[unstable(feature = "bstr", issue = "134915")]
+// impl<'a, const N: usize> From<&'a [u8; N]> for &'a ByteStr {
+//     #[inline]
+//     fn from(s: &'a [u8; N]) -> Self {
+//         ByteStr::from_bytes(s)
+//     }
+// }
+//
+// #[unstable(feature = "bstr", issue = "134915")]
+// impl<'a> From<&'a [u8]> for &'a ByteStr {
+//     #[inline]
+//     fn from(s: &'a [u8]) -> Self {
+//         ByteStr::from_bytes(s)
+//     }
+// }
+
+// Omitted due to slice-from-array-issue-113238:
+//
+// #[unstable(feature = "bstr", issue = "134915")]
+// impl<'a> From<&'a ByteStr> for &'a [u8] {
+//     #[inline]
+//     fn from(s: &'a ByteStr) -> Self {
+//         &s.0
+//     }
+// }
+//
+// #[unstable(feature = "bstr", issue = "134915")]
+// impl<'a> From<&'a mut ByteStr> for &'a mut [u8] {
+//     #[inline]
+//     fn from(s: &'a mut ByteStr) -> Self {
+//         &mut s.0
+//     }
+// }
+
+// Omitted due to inference failures
+//
+// #[unstable(feature = "bstr", issue = "134915")]
+// impl<'a> From<&'a str> for &'a ByteStr {
+//     #[inline]
+//     fn from(s: &'a str) -> Self {
+//         ByteStr::from_bytes(s.as_bytes())
+//     }
+// }
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl hash::Hash for ByteStr {
+    #[inline]
+    fn hash<H: hash::Hasher>(&self, state: &mut H) {
+        self.0.hash(state);
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<usize> for ByteStr {
+    type Output = u8;
+
+    #[inline]
+    fn index(&self, idx: usize) -> &u8 {
+        &self.0[idx]
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<RangeFull> for ByteStr {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, _: RangeFull) -> &ByteStr {
+        self
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<Range<usize>> for ByteStr {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, r: Range<usize>) -> &ByteStr {
+        ByteStr::from_bytes(&self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<RangeInclusive<usize>> for ByteStr {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, r: RangeInclusive<usize>) -> &ByteStr {
+        ByteStr::from_bytes(&self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<RangeFrom<usize>> for ByteStr {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, r: RangeFrom<usize>) -> &ByteStr {
+        ByteStr::from_bytes(&self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<RangeTo<usize>> for ByteStr {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, r: RangeTo<usize>) -> &ByteStr {
+        ByteStr::from_bytes(&self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Index<RangeToInclusive<usize>> for ByteStr {
+    type Output = ByteStr;
+
+    #[inline]
+    fn index(&self, r: RangeToInclusive<usize>) -> &ByteStr {
+        ByteStr::from_bytes(&self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<usize> for ByteStr {
+    #[inline]
+    fn index_mut(&mut self, idx: usize) -> &mut u8 {
+        &mut self.0[idx]
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<RangeFull> for ByteStr {
+    #[inline]
+    fn index_mut(&mut self, _: RangeFull) -> &mut ByteStr {
+        self
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<Range<usize>> for ByteStr {
+    #[inline]
+    fn index_mut(&mut self, r: Range<usize>) -> &mut ByteStr {
+        ByteStr::from_bytes_mut(&mut self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<RangeInclusive<usize>> for ByteStr {
+    #[inline]
+    fn index_mut(&mut self, r: RangeInclusive<usize>) -> &mut ByteStr {
+        ByteStr::from_bytes_mut(&mut self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<RangeFrom<usize>> for ByteStr {
+    #[inline]
+    fn index_mut(&mut self, r: RangeFrom<usize>) -> &mut ByteStr {
+        ByteStr::from_bytes_mut(&mut self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<RangeTo<usize>> for ByteStr {
+    #[inline]
+    fn index_mut(&mut self, r: RangeTo<usize>) -> &mut ByteStr {
+        ByteStr::from_bytes_mut(&mut self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl IndexMut<RangeToInclusive<usize>> for ByteStr {
+    #[inline]
+    fn index_mut(&mut self, r: RangeToInclusive<usize>) -> &mut ByteStr {
+        ByteStr::from_bytes_mut(&mut self.0[r])
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Eq for ByteStr {}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl PartialEq<ByteStr> for ByteStr {
+    #[inline]
+    fn eq(&self, other: &ByteStr) -> bool {
+        &self.0 == &other.0
+    }
+}
+
+#[doc(hidden)]
+#[macro_export]
+#[unstable(feature = "bstr_internals", issue = "none")]
+macro_rules! impl_partial_eq {
+    ($lhs:ty, $rhs:ty) => {
+        #[allow(unused_lifetimes)]
+        impl<'a> PartialEq<$rhs> for $lhs {
+            #[inline]
+            fn eq(&self, other: &$rhs) -> bool {
+                let other: &[u8] = other.as_ref();
+                PartialEq::eq(self.as_bytes(), other)
+            }
+        }
+
+        #[allow(unused_lifetimes)]
+        impl<'a> PartialEq<$lhs> for $rhs {
+            #[inline]
+            fn eq(&self, other: &$lhs) -> bool {
+                let this: &[u8] = self.as_ref();
+                PartialEq::eq(this, other.as_bytes())
+            }
+        }
+    };
+}
+
+#[doc(hidden)]
+#[unstable(feature = "bstr_internals", issue = "none")]
+pub use impl_partial_eq;
+
+#[doc(hidden)]
+#[macro_export]
+#[unstable(feature = "bstr_internals", issue = "none")]
+macro_rules! impl_partial_eq_ord {
+    ($lhs:ty, $rhs:ty) => {
+        $crate::bstr::impl_partial_eq!($lhs, $rhs);
+
+        #[allow(unused_lifetimes)]
+        #[unstable(feature = "bstr", issue = "134915")]
+        impl<'a> PartialOrd<$rhs> for $lhs {
+            #[inline]
+            fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
+                let other: &[u8] = other.as_ref();
+                PartialOrd::partial_cmp(self.as_bytes(), other)
+            }
+        }
+
+        #[allow(unused_lifetimes)]
+        #[unstable(feature = "bstr", issue = "134915")]
+        impl<'a> PartialOrd<$lhs> for $rhs {
+            #[inline]
+            fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
+                let this: &[u8] = self.as_ref();
+                PartialOrd::partial_cmp(this, other.as_bytes())
+            }
+        }
+    };
+}
+
+#[doc(hidden)]
+#[unstable(feature = "bstr_internals", issue = "none")]
+pub use impl_partial_eq_ord;
+
+#[doc(hidden)]
+#[macro_export]
+#[unstable(feature = "bstr_internals", issue = "none")]
+macro_rules! impl_partial_eq_n {
+    ($lhs:ty, $rhs:ty) => {
+        #[allow(unused_lifetimes)]
+        #[unstable(feature = "bstr", issue = "134915")]
+        impl<const N: usize> PartialEq<$rhs> for $lhs {
+            #[inline]
+            fn eq(&self, other: &$rhs) -> bool {
+                let other: &[u8] = other.as_ref();
+                PartialEq::eq(self.as_bytes(), other)
+            }
+        }
+
+        #[allow(unused_lifetimes)]
+        #[unstable(feature = "bstr", issue = "134915")]
+        impl<const N: usize> PartialEq<$lhs> for $rhs {
+            #[inline]
+            fn eq(&self, other: &$lhs) -> bool {
+                let this: &[u8] = self.as_ref();
+                PartialEq::eq(this, other.as_bytes())
+            }
+        }
+    };
+}
+
+#[doc(hidden)]
+#[unstable(feature = "bstr_internals", issue = "none")]
+pub use impl_partial_eq_n;
+
+// PartialOrd with `[u8]` omitted to avoid inference failures
+impl_partial_eq!(ByteStr, [u8]);
+// PartialOrd with `&[u8]` omitted to avoid inference failures
+impl_partial_eq!(ByteStr, &[u8]);
+// PartialOrd with `str` omitted to avoid inference failures
+impl_partial_eq!(ByteStr, str);
+// PartialOrd with `&str` omitted to avoid inference failures
+impl_partial_eq!(ByteStr, &str);
+// PartialOrd with `[u8; N]` omitted to avoid inference failures
+impl_partial_eq_n!(ByteStr, [u8; N]);
+// PartialOrd with `[u8; N]` omitted to avoid inference failures
+impl_partial_eq_n!(ByteStr, &[u8; N]);
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl Ord for ByteStr {
+    #[inline]
+    fn cmp(&self, other: &ByteStr) -> Ordering {
+        Ord::cmp(&self.0, &other.0)
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl PartialOrd for ByteStr {
+    #[inline]
+    fn partial_cmp(&self, other: &ByteStr) -> Option<Ordering> {
+        PartialOrd::partial_cmp(&self.0, &other.0)
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl<'a> TryFrom<&'a ByteStr> for &'a str {
+    type Error = crate::str::Utf8Error;
+
+    #[inline]
+    fn try_from(s: &'a ByteStr) -> Result<Self, Self::Error> {
+        crate::str::from_utf8(&s.0)
+    }
+}
+
+#[unstable(feature = "bstr", issue = "134915")]
+impl<'a> TryFrom<&'a mut ByteStr> for &'a mut str {
+    type Error = crate::str::Utf8Error;
+
+    #[inline]
+    fn try_from(s: &'a mut ByteStr) -> Result<Self, Self::Error> {
+        crate::str::from_utf8_mut(&mut s.0)
+    }
+}
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 306d565a77e..20187e478aa 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -22,8 +22,8 @@
 //! (mutable via `&T`), in contrast with typical Rust types that exhibit 'inherited mutability'
 //! (mutable only via `&mut T`).
 //!
-//! Cell types come in three flavors: `Cell<T>`, `RefCell<T>`, and `OnceCell<T>`. Each provides
-//! a different way of providing safe interior mutability.
+//! Cell types come in four flavors: `Cell<T>`, `RefCell<T>`, `OnceCell<T>`, and `LazyCell<T>`.
+//! Each provides a different way of providing safe interior mutability.
 //!
 //! ## `Cell<T>`
 //!
diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs
index ec1aed53eaf..00300328b64 100644
--- a/library/core/src/clone.rs
+++ b/library/core/src/clone.rs
@@ -311,6 +311,16 @@ unsafe impl CloneToUninit for crate::ffi::CStr {
     }
 }
 
+#[unstable(feature = "bstr", issue = "134915")]
+unsafe impl CloneToUninit for crate::bstr::ByteStr {
+    #[inline]
+    #[cfg_attr(debug_assertions, track_caller)]
+    unsafe fn clone_to_uninit(&self, dst: *mut u8) {
+        // SAFETY: ByteStr is a `#[repr(transparent)]` wrapper around `[u8]`
+        unsafe { self.as_bytes().clone_to_uninit(dst) }
+    }
+}
+
 /// Implementations of `Clone` for primitive types.
 ///
 /// Implementations that cannot be described in Rust
diff --git a/library/core/src/escape.rs b/library/core/src/escape.rs
index 0685f525dca..0c3329f676e 100644
--- a/library/core/src/escape.rs
+++ b/library/core/src/escape.rs
@@ -163,28 +163,28 @@ pub(crate) struct EscapeIterInner<const N: usize> {
 }
 
 impl<const N: usize> EscapeIterInner<N> {
-    pub const fn backslash(c: ascii::Char) -> Self {
+    pub(crate) const fn backslash(c: ascii::Char) -> Self {
         let (data, range) = backslash(c);
         Self { data, alive: range }
     }
 
-    pub const fn ascii(c: u8) -> Self {
+    pub(crate) const fn ascii(c: u8) -> Self {
         let (data, range) = escape_ascii(c);
         Self { data, alive: range }
     }
 
-    pub const fn unicode(c: char) -> Self {
+    pub(crate) const fn unicode(c: char) -> Self {
         let (data, range) = escape_unicode(c);
         Self { data, alive: range }
     }
 
     #[inline]
-    pub const fn empty() -> Self {
+    pub(crate) const fn empty() -> Self {
         Self { data: [ascii::Char::Null; N], alive: 0..0 }
     }
 
     #[inline]
-    pub fn as_ascii(&self) -> &[ascii::Char] {
+    pub(crate) fn as_ascii(&self) -> &[ascii::Char] {
         // SAFETY: `self.alive` is guaranteed to be a valid range for indexing `self.data`.
         unsafe {
             self.data.get_unchecked(usize::from(self.alive.start)..usize::from(self.alive.end))
@@ -192,34 +192,34 @@ impl<const N: usize> EscapeIterInner<N> {
     }
 
     #[inline]
-    pub fn as_str(&self) -> &str {
+    pub(crate) fn as_str(&self) -> &str {
         self.as_ascii().as_str()
     }
 
     #[inline]
-    pub fn len(&self) -> usize {
+    pub(crate) fn len(&self) -> usize {
         usize::from(self.alive.end - self.alive.start)
     }
 
-    pub fn next(&mut self) -> Option<u8> {
+    pub(crate) fn next(&mut self) -> Option<u8> {
         let i = self.alive.next()?;
 
         // SAFETY: `i` is guaranteed to be a valid index for `self.data`.
         unsafe { Some(self.data.get_unchecked(usize::from(i)).to_u8()) }
     }
 
-    pub fn next_back(&mut self) -> Option<u8> {
+    pub(crate) fn next_back(&mut self) -> Option<u8> {
         let i = self.alive.next_back()?;
 
         // SAFETY: `i` is guaranteed to be a valid index for `self.data`.
         unsafe { Some(self.data.get_unchecked(usize::from(i)).to_u8()) }
     }
 
-    pub fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
+    pub(crate) fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         self.alive.advance_by(n)
     }
 
-    pub fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
+    pub(crate) fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         self.alive.advance_back_by(n)
     }
 }
diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs
index 5f32775822b..79d094556c4 100644
--- a/library/core/src/ffi/mod.rs
+++ b/library/core/src/ffi/mod.rs
@@ -172,10 +172,10 @@ mod c_char_definition {
                 target_arch = "xtensa",
             )
         ))] {
-            pub type c_char = u8;
+            pub(super) type c_char = u8;
         } else {
             // On every other target, c_char is signed.
-            pub type c_char = i8;
+            pub(super) type c_char = i8;
         }
     }
 }
@@ -183,11 +183,11 @@ mod c_char_definition {
 mod c_int_definition {
     cfg_if! {
         if #[cfg(any(target_arch = "avr", target_arch = "msp430"))] {
-            pub type c_int = i16;
-            pub type c_uint = u16;
+            pub(super) type c_int = i16;
+            pub(super) type c_uint = u16;
         } else {
-            pub type c_int = i32;
-            pub type c_uint = u32;
+            pub(super) type c_int = i32;
+            pub(super) type c_uint = u32;
         }
     }
 }
@@ -195,12 +195,12 @@ mod c_int_definition {
 mod c_long_definition {
     cfg_if! {
         if #[cfg(all(target_pointer_width = "64", not(windows)))] {
-            pub type c_long = i64;
-            pub type c_ulong = u64;
+            pub(super) type c_long = i64;
+            pub(super) type c_ulong = u64;
         } else {
             // The minimal size of `long` in the C standard is 32 bits
-            pub type c_long = i32;
-            pub type c_ulong = u32;
+            pub(super) type c_long = i32;
+            pub(super) type c_ulong = u32;
         }
     }
 }
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index 9c054b99a27..80f6e32b6b2 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -597,3 +597,138 @@ pub const fn black_box<T>(dummy: T) -> T {
 pub const fn must_use<T>(value: T) -> T {
     value
 }
+
+/// Hints to the compiler that a branch condition is likely to be true.
+/// Returns the value passed to it.
+///
+/// It can be used with `if` or boolean `match` expressions.
+///
+/// When used outside of a branch condition, it may still influence a nearby branch, but
+/// probably will not have any effect.
+///
+/// It can also be applied to parts of expressions, such as `likely(a) && unlikely(b)`, or to
+/// compound expressions, such as `likely(a && b)`. When applied to compound expressions, it has
+/// the following effect:
+/// ```text
+///     likely(!a) => !unlikely(a)
+///     likely(a && b) => likely(a) && likely(b)
+///     likely(a || b) => a || likely(b)
+/// ```
+///
+/// See also the function [`cold_path()`] which may be more appropriate for idiomatic Rust code.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(likely_unlikely)]
+/// use core::hint::likely;
+///
+/// fn foo(x: i32) {
+///     if likely(x > 0) {
+///         println!("this branch is likely to be taken");
+///     } else {
+///         println!("this branch is unlikely to be taken");
+///     }
+///
+///     match likely(x > 0) {
+///         true => println!("this branch is likely to be taken"),
+///         false => println!("this branch is unlikely to be taken"),
+///     }
+///
+///     // Use outside of a branch condition may still influence a nearby branch
+///     let cond = likely(x != 0);
+///     if cond {
+///         println!("this branch is likely to be taken");
+///     }
+/// }
+/// ```
+///
+///
+#[unstable(feature = "likely_unlikely", issue = "26179")]
+#[inline(always)]
+pub const fn likely(b: bool) -> bool {
+    crate::intrinsics::likely(b)
+}
+
+/// Hints to the compiler that a branch condition is unlikely to be true.
+/// Returns the value passed to it.
+///
+/// It can be used with `if` or boolean `match` expressions.
+///
+/// When used outside of a branch condition, it may still influence a nearby branch, but
+/// probably will not have any effect.
+///
+/// It can also be applied to parts of expressions, such as `likely(a) && unlikely(b)`, or to
+/// compound expressions, such as `unlikely(a && b)`. When applied to compound expressions, it has
+/// the following effect:
+/// ```text
+///     unlikely(!a) => !likely(a)
+///     unlikely(a && b) => a && unlikely(b)
+///     unlikely(a || b) => unlikely(a) || unlikely(b)
+/// ```
+///
+/// See also the function [`cold_path()`] which may be more appropriate for idiomatic Rust code.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(likely_unlikely)]
+/// use core::hint::unlikely;
+///
+/// fn foo(x: i32) {
+///     if unlikely(x > 0) {
+///         println!("this branch is unlikely to be taken");
+///     } else {
+///         println!("this branch is likely to be taken");
+///     }
+///
+///     match unlikely(x > 0) {
+///         true => println!("this branch is unlikely to be taken"),
+///         false => println!("this branch is likely to be taken"),
+///     }
+///
+///     // Use outside of a branch condition may still influence a nearby branch
+///     let cond = unlikely(x != 0);
+///     if cond {
+///         println!("this branch is likely to be taken");
+///     }
+/// }
+/// ```
+#[unstable(feature = "likely_unlikely", issue = "26179")]
+#[inline(always)]
+pub const fn unlikely(b: bool) -> bool {
+    crate::intrinsics::unlikely(b)
+}
+
+/// Hints to the compiler that given path is cold, i.e., unlikely to be taken. The compiler may
+/// choose to optimize paths that are not cold at the expense of paths that are cold.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(cold_path)]
+/// use core::hint::cold_path;
+///
+/// fn foo(x: &[i32]) {
+///     if let Some(first) = x.get(0) {
+///         // this is the fast path
+///     } else {
+///         // this path is unlikely
+///         cold_path();
+///     }
+/// }
+///
+/// fn bar(x: i32) -> i32 {
+///     match x {
+///         1 => 10,
+///         2 => 100,
+///         3 => { cold_path(); 1000 }, // this branch is unlikely
+///         _ => { cold_path(); 10000 }, // this is also unlikely
+///     }
+/// }
+/// ```
+#[unstable(feature = "cold_path", issue = "26179")]
+#[inline(always)]
+pub const fn cold_path() {
+    crate::intrinsics::cold_path()
+}
diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs
index 834f44c7790..55dcf7cd47e 100644
--- a/library/core/src/intrinsics/mir.rs
+++ b/library/core/src/intrinsics/mir.rs
@@ -233,7 +233,7 @@
 //!
 //!  - Operands implicitly convert to `Use` rvalues.
 //!  - `&`, `&mut`, `addr_of!`, and `addr_of_mut!` all work to create their associated rvalue.
-//!  - [`Discriminant`] and [`CopyForDeref`] have associated functions.
+//!  - [`Discriminant`], [`Len`], and [`CopyForDeref`] have associated functions.
 //!  - Unary and binary operations use their normal Rust syntax - `a * b`, `!c`, etc.
 //!  - The binary operation `Offset` can be created via [`Offset`].
 //!  - Checked binary operations are represented by wrapping the associated binop in [`Checked`].
@@ -401,6 +401,7 @@ define!("mir_storage_dead", fn StorageDead<T>(local: T));
 define!("mir_assume", fn Assume(operand: bool));
 define!("mir_deinit", fn Deinit<T>(place: T));
 define!("mir_checked", fn Checked<T>(binop: T) -> (T, bool));
+define!("mir_len", fn Len<T>(place: T) -> usize);
 define!(
     "mir_ptr_metadata",
     fn PtrMetadata<P: ?Sized>(place: *const P) -> <P as ::core::ptr::Pointee>::Metadata
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index e845bb34426..01ed3cc69a2 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -101,6 +101,7 @@
 #![warn(multiple_supertrait_upcastable)]
 #![allow(internal_features)]
 #![deny(ffi_unwind_calls)]
+#![warn(unreachable_pub)]
 // Do not check link redundancy on bootstraping phase
 #![allow(rustdoc::redundant_explicit_links)]
 #![warn(rustdoc::unescaped_backticks)]
@@ -110,6 +111,8 @@
 #![feature(array_ptr_get)]
 #![feature(asm_experimental_arch)]
 #![feature(bigint_helper_methods)]
+#![feature(bstr)]
+#![feature(bstr_internals)]
 #![feature(const_carrying_mul_add)]
 #![feature(const_eval_select)]
 #![feature(core_intrinsics)]
@@ -335,6 +338,8 @@ pub mod ascii;
 pub mod asserting;
 #[unstable(feature = "async_iterator", issue = "79024")]
 pub mod async_iter;
+#[unstable(feature = "bstr", issue = "134915")]
+pub mod bstr;
 pub mod cell;
 pub mod char;
 pub mod ffi;
@@ -396,7 +401,8 @@ pub mod primitive;
     unused_imports,
     unsafe_op_in_unsafe_fn,
     ambiguous_glob_reexports,
-    deprecated_in_future
+    deprecated_in_future,
+    unreachable_pub
 )]
 #[allow(rustdoc::bare_urls)]
 mod core_arch;
diff --git a/library/core/src/net/display_buffer.rs b/library/core/src/net/display_buffer.rs
index a7d12217081..625ad5401f5 100644
--- a/library/core/src/net/display_buffer.rs
+++ b/library/core/src/net/display_buffer.rs
@@ -2,19 +2,19 @@ use crate::mem::MaybeUninit;
 use crate::{fmt, str};
 
 /// Used for slow path in `Display` implementations when alignment is required.
-pub struct DisplayBuffer<const SIZE: usize> {
+pub(super) struct DisplayBuffer<const SIZE: usize> {
     buf: [MaybeUninit<u8>; SIZE],
     len: usize,
 }
 
 impl<const SIZE: usize> DisplayBuffer<SIZE> {
     #[inline]
-    pub const fn new() -> Self {
+    pub(super) const fn new() -> Self {
         Self { buf: [MaybeUninit::uninit(); SIZE], len: 0 }
     }
 
     #[inline]
-    pub fn as_str(&self) -> &str {
+    pub(super) fn as_str(&self) -> &str {
         // SAFETY: `buf` is only written to by the `fmt::Write::write_str` implementation
         // which writes a valid UTF-8 string to `buf` and correctly sets `len`.
         unsafe {
diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs
index 7dd5c214012..b11ba056853 100644
--- a/library/core/src/net/ip_addr.rs
+++ b/library/core/src/net/ip_addr.rs
@@ -1539,8 +1539,9 @@ impl Ipv6Addr {
     /// // Addresses reserved for benchmarking (`2001:2::/48`)
     /// assert_eq!(Ipv6Addr::new(0x2001, 2, 0, 0, 0, 0, 0, 1,).is_global(), false);
     ///
-    /// // Addresses reserved for documentation (`2001:db8::/32`)
+    /// // Addresses reserved for documentation (`2001:db8::/32` and `3fff::/20`)
     /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1).is_global(), false);
+    /// assert_eq!(Ipv6Addr::new(0x3fff, 0, 0, 0, 0, 0, 0, 0).is_global(), false);
     ///
     /// // Unique local addresses (`fc00::/7`)
     /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 1).is_global(), false);
@@ -1686,11 +1687,12 @@ impl Ipv6Addr {
     }
 
     /// Returns [`true`] if this is an address reserved for documentation
-    /// (`2001:db8::/32`).
+    /// (`2001:db8::/32` and `3fff::/20`).
     ///
-    /// This property is defined in [IETF RFC 3849].
+    /// This property is defined by [IETF RFC 3849] and [IETF RFC 9637].
     ///
     /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849
+    /// [IETF RFC 9637]: https://tools.ietf.org/html/rfc9637
     ///
     /// # Examples
     ///
@@ -1701,12 +1703,13 @@ impl Ipv6Addr {
     ///
     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false);
     /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true);
+    /// assert_eq!(Ipv6Addr::new(0x3fff, 0, 0, 0, 0, 0, 0, 0).is_documentation(), true);
     /// ```
     #[unstable(feature = "ip", issue = "27709")]
     #[must_use]
     #[inline]
     pub const fn is_documentation(&self) -> bool {
-        (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)
+        matches!(self.segments(), [0x2001, 0xdb8, ..] | [0x3fff, 0..=0x0fff, ..])
     }
 
     /// Returns [`true`] if this is an address reserved for benchmarking (`2001:2::/48`).
diff --git a/library/core/src/num/dec2flt/decimal.rs b/library/core/src/num/dec2flt/decimal.rs
index be9c0eccd5e..b37724ba62d 100644
--- a/library/core/src/num/dec2flt/decimal.rs
+++ b/library/core/src/num/dec2flt/decimal.rs
@@ -12,7 +12,7 @@
 use crate::num::dec2flt::common::{ByteSlice, is_8digits};
 
 #[derive(Clone)]
-pub struct Decimal {
+pub(super) struct Decimal {
     /// The number of significant digits in the decimal.
     pub num_digits: usize,
     /// The offset of the decimal point in the significant digits.
@@ -55,13 +55,13 @@ impl Decimal {
     ///
     /// In Python:
     ///     `-emin + p2 + math.floor((emin+ 1)*math.log(2, b)-math.log(1-2**(-p2), b))`
-    pub const MAX_DIGITS: usize = 768;
+    pub(super) const MAX_DIGITS: usize = 768;
     /// The max digits that can be exactly represented in a 64-bit integer.
-    pub const MAX_DIGITS_WITHOUT_OVERFLOW: usize = 19;
-    pub const DECIMAL_POINT_RANGE: i32 = 2047;
+    pub(super) const MAX_DIGITS_WITHOUT_OVERFLOW: usize = 19;
+    pub(super) const DECIMAL_POINT_RANGE: i32 = 2047;
 
     /// Append a digit to the buffer.
-    pub fn try_add_digit(&mut self, digit: u8) {
+    pub(super) fn try_add_digit(&mut self, digit: u8) {
         if self.num_digits < Self::MAX_DIGITS {
             self.digits[self.num_digits] = digit;
         }
@@ -69,7 +69,7 @@ impl Decimal {
     }
 
     /// Trim trailing zeros from the buffer.
-    pub fn trim(&mut self) {
+    pub(super) fn trim(&mut self) {
         // All of the following calls to `Decimal::trim` can't panic because:
         //
         //  1. `parse_decimal` sets `num_digits` to a max of `Decimal::MAX_DIGITS`.
@@ -83,7 +83,7 @@ impl Decimal {
         }
     }
 
-    pub fn round(&self) -> u64 {
+    pub(super) fn round(&self) -> u64 {
         if self.num_digits == 0 || self.decimal_point < 0 {
             return 0;
         } else if self.decimal_point > 18 {
@@ -111,7 +111,7 @@ impl Decimal {
     }
 
     /// Computes decimal * 2^shift.
-    pub fn left_shift(&mut self, shift: usize) {
+    pub(super) fn left_shift(&mut self, shift: usize) {
         if self.num_digits == 0 {
             return;
         }
@@ -152,7 +152,7 @@ impl Decimal {
     }
 
     /// Computes decimal * 2^-shift.
-    pub fn right_shift(&mut self, shift: usize) {
+    pub(super) fn right_shift(&mut self, shift: usize) {
         let mut read_index = 0;
         let mut write_index = 0;
         let mut n = 0_u64;
@@ -202,7 +202,7 @@ impl Decimal {
 }
 
 /// Parse a big integer representation of the float as a decimal.
-pub fn parse_decimal(mut s: &[u8]) -> Decimal {
+pub(super) fn parse_decimal(mut s: &[u8]) -> Decimal {
     let mut d = Decimal::default();
     let start = s;
 
diff --git a/library/core/src/num/dec2flt/fpu.rs b/library/core/src/num/dec2flt/fpu.rs
index 8d62684f8d3..daeee1755b0 100644
--- a/library/core/src/num/dec2flt/fpu.rs
+++ b/library/core/src/num/dec2flt/fpu.rs
@@ -1,7 +1,7 @@
 //! Platform-specific, assembly instructions to avoid
 //! intermediate rounding on architectures with FPUs.
 
-pub use fpu_precision::set_precision;
+pub(super) use fpu_precision::set_precision;
 
 // On x86, the x87 FPU is used for float operations if the SSE/SSE2 extensions are not available.
 // The x87 FPU operates with 80 bits of precision by default, which means that operations will
@@ -42,7 +42,7 @@ mod fpu_precision {
     ///  - 0b10, double precision i.e., 64-bits
     ///  - 0b11, double extended precision i.e., 80-bits (default state)
     /// The 0b01 value is reserved and should not be used.
-    pub struct FPUControlWord(u16);
+    pub(crate) struct FPUControlWord(u16);
 
     fn set_cw(cw: u16) {
         // SAFETY: the `fldcw` instruction has been audited to be able to work correctly with
@@ -57,7 +57,7 @@ mod fpu_precision {
     }
 
     /// Sets the precision field of the FPU to `T` and returns a `FPUControlWord`.
-    pub fn set_precision<T>() -> FPUControlWord {
+    pub(crate) fn set_precision<T>() -> FPUControlWord {
         let mut cw = 0_u16;
 
         // Compute the value for the Precision Control field that is appropriate for `T`.
@@ -97,5 +97,5 @@ mod fpu_precision {
 // precision of the computation is determined on a per-operation basis.
 #[cfg(any(not(target_arch = "x86"), target_feature = "sse2"))]
 mod fpu_precision {
-    pub fn set_precision<T>() {}
+    pub(crate) fn set_precision<T>() {}
 }
diff --git a/library/core/src/num/dec2flt/table.rs b/library/core/src/num/dec2flt/table.rs
index 4856074a62b..942c2eacfd2 100644
--- a/library/core/src/num/dec2flt/table.rs
+++ b/library/core/src/num/dec2flt/table.rs
@@ -6,16 +6,17 @@
 //!
 //! DO NOT MODIFY: Generated by `src/etc/dec2flt_table.py`
 
-pub const SMALLEST_POWER_OF_FIVE: i32 = -342;
-pub const LARGEST_POWER_OF_FIVE: i32 = 308;
-pub const N_POWERS_OF_FIVE: usize = (LARGEST_POWER_OF_FIVE - SMALLEST_POWER_OF_FIVE + 1) as usize;
+pub(super) const SMALLEST_POWER_OF_FIVE: i32 = -342;
+pub(super) const LARGEST_POWER_OF_FIVE: i32 = 308;
+pub(super) const N_POWERS_OF_FIVE: usize =
+    (LARGEST_POWER_OF_FIVE - SMALLEST_POWER_OF_FIVE + 1) as usize;
 
 // Use static to avoid long compile times: Rust compiler errors
 // can have the entire table compiled multiple times, and then
 // emit code multiple times, even if it's stripped out in
 // the final binary.
 #[rustfmt::skip]
-pub static POWER_OF_FIVE_128: [(u64, u64); N_POWERS_OF_FIVE] = [
+pub(super) static POWER_OF_FIVE_128: [(u64, u64); N_POWERS_OF_FIVE] = [
     (0xeef453d6923bd65a, 0x113faa2906a13b3f), // 5^-342
     (0x9558b4661b6565f8, 0x4ac7ca59a424c507), // 5^-341
     (0xbaaee17fa23ebf76, 0x5d79bcf00d2df649), // 5^-340
diff --git a/library/core/src/num/int_log10.rs b/library/core/src/num/int_log10.rs
index 0ce31b40a38..28a3f5d880a 100644
--- a/library/core/src/num/int_log10.rs
+++ b/library/core/src/num/int_log10.rs
@@ -3,7 +3,7 @@
 
 // 0 < val <= u8::MAX
 #[inline]
-pub const fn u8(val: u8) -> u32 {
+pub(super) const fn u8(val: u8) -> u32 {
     let val = val as u32;
 
     // For better performance, avoid branches by assembling the solution
@@ -45,13 +45,13 @@ const fn less_than_5(val: u32) -> u32 {
 
 // 0 < val <= u16::MAX
 #[inline]
-pub const fn u16(val: u16) -> u32 {
+pub(super) const fn u16(val: u16) -> u32 {
     less_than_5(val as u32)
 }
 
 // 0 < val <= u32::MAX
 #[inline]
-pub const fn u32(mut val: u32) -> u32 {
+pub(super) const fn u32(mut val: u32) -> u32 {
     let mut log = 0;
     if val >= 100_000 {
         val /= 100_000;
@@ -62,7 +62,7 @@ pub const fn u32(mut val: u32) -> u32 {
 
 // 0 < val <= u64::MAX
 #[inline]
-pub const fn u64(mut val: u64) -> u32 {
+pub(super) const fn u64(mut val: u64) -> u32 {
     let mut log = 0;
     if val >= 10_000_000_000 {
         val /= 10_000_000_000;
@@ -77,7 +77,7 @@ pub const fn u64(mut val: u64) -> u32 {
 
 // 0 < val <= u128::MAX
 #[inline]
-pub const fn u128(mut val: u128) -> u32 {
+pub(super) const fn u128(mut val: u128) -> u32 {
     let mut log = 0;
     if val >= 100_000_000_000_000_000_000_000_000_000_000 {
         val /= 100_000_000_000_000_000_000_000_000_000_000;
@@ -93,49 +93,49 @@ pub const fn u128(mut val: u128) -> u32 {
 
 #[cfg(target_pointer_width = "16")]
 #[inline]
-pub const fn usize(val: usize) -> u32 {
+pub(super) const fn usize(val: usize) -> u32 {
     u16(val as _)
 }
 
 #[cfg(target_pointer_width = "32")]
 #[inline]
-pub const fn usize(val: usize) -> u32 {
+pub(super) const fn usize(val: usize) -> u32 {
     u32(val as _)
 }
 
 #[cfg(target_pointer_width = "64")]
 #[inline]
-pub const fn usize(val: usize) -> u32 {
+pub(super) const fn usize(val: usize) -> u32 {
     u64(val as _)
 }
 
 // 0 < val <= i8::MAX
 #[inline]
-pub const fn i8(val: i8) -> u32 {
+pub(super) const fn i8(val: i8) -> u32 {
     u8(val as u8)
 }
 
 // 0 < val <= i16::MAX
 #[inline]
-pub const fn i16(val: i16) -> u32 {
+pub(super) const fn i16(val: i16) -> u32 {
     u16(val as u16)
 }
 
 // 0 < val <= i32::MAX
 #[inline]
-pub const fn i32(val: i32) -> u32 {
+pub(super) const fn i32(val: i32) -> u32 {
     u32(val as u32)
 }
 
 // 0 < val <= i64::MAX
 #[inline]
-pub const fn i64(val: i64) -> u32 {
+pub(super) const fn i64(val: i64) -> u32 {
     u64(val as u64)
 }
 
 // 0 < val <= i128::MAX
 #[inline]
-pub const fn i128(val: i128) -> u32 {
+pub(super) const fn i128(val: i128) -> u32 {
     u128(val as u128)
 }
 
@@ -143,6 +143,6 @@ pub const fn i128(val: i128) -> u32 {
 /// on every single primitive type.
 #[cold]
 #[track_caller]
-pub const fn panic_for_nonpositive_argument() -> ! {
+pub(super) const fn panic_for_nonpositive_argument() -> ! {
     panic!("argument of integer logarithm must be positive")
 }
diff --git a/library/core/src/num/int_sqrt.rs b/library/core/src/num/int_sqrt.rs
index 601e81f6993..c7a322c08c1 100644
--- a/library/core/src/num/int_sqrt.rs
+++ b/library/core/src/num/int_sqrt.rs
@@ -37,7 +37,7 @@ const U8_ISQRT_WITH_REMAINDER: [(u8, u8); 256] = {
 #[must_use = "this returns the result of the operation, \
               without modifying the original"]
 #[inline]
-pub const fn u8(n: u8) -> u8 {
+pub(super) const fn u8(n: u8) -> u8 {
     U8_ISQRT_WITH_REMAINDER[n as usize].0
 }
 
@@ -58,7 +58,7 @@ macro_rules! signed_fn {
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
-        pub const unsafe fn $SignedT(n: $SignedT) -> $SignedT {
+        pub(super) const unsafe fn $SignedT(n: $SignedT) -> $SignedT {
             debug_assert!(n >= 0, "Negative input inside `isqrt`.");
             $UnsignedT(n as $UnsignedT) as $SignedT
         }
@@ -83,7 +83,7 @@ macro_rules! unsigned_fn {
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
-        pub const fn $UnsignedT(mut n: $UnsignedT) -> $UnsignedT {
+        pub(super) const fn $UnsignedT(mut n: $UnsignedT) -> $UnsignedT {
             if n <= <$HalfBitsT>::MAX as $UnsignedT {
                 $HalfBitsT(n as $HalfBitsT) as $UnsignedT
             } else {
@@ -311,6 +311,6 @@ unsigned_fn!(u128, u64, u128_stages);
 /// on every single primitive type.
 #[cold]
 #[track_caller]
-pub const fn panic_for_negative_argument() -> ! {
+pub(super) const fn panic_for_negative_argument() -> ! {
     panic!("argument of integer square root cannot be negative")
 }
diff --git a/library/core/src/num/overflow_panic.rs b/library/core/src/num/overflow_panic.rs
index 203037ffb43..e30573dd3f3 100644
--- a/library/core/src/num/overflow_panic.rs
+++ b/library/core/src/num/overflow_panic.rs
@@ -4,48 +4,48 @@
 
 #[cold]
 #[track_caller]
-pub const fn add() -> ! {
+pub(super) const fn add() -> ! {
     panic!("attempt to add with overflow")
 }
 
 #[cold]
 #[track_caller]
-pub const fn sub() -> ! {
+pub(super) const fn sub() -> ! {
     panic!("attempt to subtract with overflow")
 }
 
 #[cold]
 #[track_caller]
-pub const fn mul() -> ! {
+pub(super) const fn mul() -> ! {
     panic!("attempt to multiply with overflow")
 }
 
 #[cold]
 #[track_caller]
-pub const fn div() -> ! {
+pub(super) const fn div() -> ! {
     panic!("attempt to divide with overflow")
 }
 
 #[cold]
 #[track_caller]
-pub const fn rem() -> ! {
+pub(super) const fn rem() -> ! {
     panic!("attempt to calculate the remainder with overflow")
 }
 
 #[cold]
 #[track_caller]
-pub const fn neg() -> ! {
+pub(super) const fn neg() -> ! {
     panic!("attempt to negate with overflow")
 }
 
 #[cold]
 #[track_caller]
-pub const fn shr() -> ! {
+pub(super) const fn shr() -> ! {
     panic!("attempt to shift right with overflow")
 }
 
 #[cold]
 #[track_caller]
-pub const fn shl() -> ! {
+pub(super) const fn shl() -> ! {
     panic!("attempt to shift left with overflow")
 }
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 404e4bcffd3..c8433b3bb16 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -2663,8 +2663,8 @@ macro_rules! uint_impl {
         ///
         /// Basic usage:
         ///
-        /// Please note that this example is shared between integer types.
-        /// Which explains why `u32` is used here.
+        /// Please note that this example is shared between integer types,
+        /// which explains why `u32` is used here.
         ///
         /// ```
         /// #![feature(bigint_helper_methods)]
@@ -2677,6 +2677,35 @@ macro_rules! uint_impl {
             "(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX));"
         )]
         /// ```
+        ///
+        /// This is the core per-digit operation for "grade school" O(n²) multiplication.
+        ///
+        /// Please note that this example is shared between integer types,
+        /// using `u8` for simplicity of the demonstration.
+        ///
+        /// ```
+        /// #![feature(bigint_helper_methods)]
+        ///
+        /// fn quadratic_mul<const N: usize>(a: [u8; N], b: [u8; N]) -> [u8; N] {
+        ///     let mut out = [0; N];
+        ///     for j in 0..N {
+        ///         let mut carry = 0;
+        ///         for i in 0..(N - j) {
+        ///             (out[j + i], carry) = u8::carrying_mul_add(a[i], b[j], out[j + i], carry);
+        ///         }
+        ///     }
+        ///     out
+        /// }
+        ///
+        /// // -1 * -1 == 1
+        /// assert_eq!(quadratic_mul([0xFF; 3], [0xFF; 3]), [1, 0, 0]);
+        ///
+        /// assert_eq!(u32::wrapping_mul(0x9e3779b9, 0x7f4a7c15), 0xCFFC982D);
+        /// assert_eq!(
+        ///     quadratic_mul(u32::to_le_bytes(0x9e3779b9), u32::to_le_bytes(0x7f4a7c15)),
+        ///     u32::to_le_bytes(0xCFFC982D)
+        /// );
+        /// ```
         #[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, \
diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs
index 1156b389e28..55fa91d0b9f 100644
--- a/library/core/src/num/wrapping.rs
+++ b/library/core/src/num/wrapping.rs
@@ -1058,33 +1058,33 @@ mod shift_max {
 
     #[cfg(target_pointer_width = "16")]
     mod platform {
-        pub const usize: u32 = super::u16;
-        pub const isize: u32 = super::i16;
+        pub(crate) const usize: u32 = super::u16;
+        pub(crate) const isize: u32 = super::i16;
     }
 
     #[cfg(target_pointer_width = "32")]
     mod platform {
-        pub const usize: u32 = super::u32;
-        pub const isize: u32 = super::i32;
+        pub(crate) const usize: u32 = super::u32;
+        pub(crate) const isize: u32 = super::i32;
     }
 
     #[cfg(target_pointer_width = "64")]
     mod platform {
-        pub const usize: u32 = super::u64;
-        pub const isize: u32 = super::i64;
+        pub(crate) const usize: u32 = super::u64;
+        pub(crate) const isize: u32 = super::i64;
     }
 
-    pub const i8: u32 = (1 << 3) - 1;
-    pub const i16: u32 = (1 << 4) - 1;
-    pub const i32: u32 = (1 << 5) - 1;
-    pub const i64: u32 = (1 << 6) - 1;
-    pub const i128: u32 = (1 << 7) - 1;
-    pub use self::platform::isize;
-
-    pub const u8: u32 = i8;
-    pub const u16: u32 = i16;
-    pub const u32: u32 = i32;
-    pub const u64: u32 = i64;
-    pub const u128: u32 = i128;
-    pub use self::platform::usize;
+    pub(super) const i8: u32 = (1 << 3) - 1;
+    pub(super) const i16: u32 = (1 << 4) - 1;
+    pub(super) const i32: u32 = (1 << 5) - 1;
+    pub(super) const i64: u32 = (1 << 6) - 1;
+    pub(super) const i128: u32 = (1 << 7) - 1;
+    pub(super) use self::platform::isize;
+
+    pub(super) const u8: u32 = i8;
+    pub(super) const u16: u32 = i16;
+    pub(super) const u32: u32 = i32;
+    pub(super) const u64: u32 = i64;
+    pub(super) const u128: u32 = i128;
+    pub(super) use self::platform::usize;
 }
diff --git a/library/core/src/ops/index_range.rs b/library/core/src/ops/index_range.rs
index dce3514a159..b82184b15b2 100644
--- a/library/core/src/ops/index_range.rs
+++ b/library/core/src/ops/index_range.rs
@@ -18,7 +18,7 @@ impl IndexRange {
     /// # Safety
     /// - `start <= end`
     #[inline]
-    pub const unsafe fn new_unchecked(start: usize, end: usize) -> Self {
+    pub(crate) const unsafe fn new_unchecked(start: usize, end: usize) -> Self {
         ub_checks::assert_unsafe_precondition!(
             check_library_ub,
             "IndexRange::new_unchecked requires `start <= end`",
@@ -28,22 +28,22 @@ impl IndexRange {
     }
 
     #[inline]
-    pub const fn zero_to(end: usize) -> Self {
+    pub(crate) const fn zero_to(end: usize) -> Self {
         IndexRange { start: 0, end }
     }
 
     #[inline]
-    pub const fn start(&self) -> usize {
+    pub(crate) const fn start(&self) -> usize {
         self.start
     }
 
     #[inline]
-    pub const fn end(&self) -> usize {
+    pub(crate) const fn end(&self) -> usize {
         self.end
     }
 
     #[inline]
-    pub const fn len(&self) -> usize {
+    pub(crate) const fn len(&self) -> usize {
         // SAFETY: By invariant, this cannot wrap
         // Using the intrinsic because a UB check here impedes LLVM optimization. (#131563)
         unsafe { crate::intrinsics::unchecked_sub(self.end, self.start) }
@@ -79,7 +79,7 @@ impl IndexRange {
     ///
     /// This is designed to help implement `Iterator::advance_by`.
     #[inline]
-    pub fn take_prefix(&mut self, n: usize) -> Self {
+    pub(crate) fn take_prefix(&mut self, n: usize) -> Self {
         let mid = if n <= self.len() {
             // SAFETY: We just checked that this will be between start and end,
             // and thus the addition cannot overflow.
@@ -99,7 +99,7 @@ impl IndexRange {
     ///
     /// This is designed to help implement `Iterator::advance_back_by`.
     #[inline]
-    pub fn take_suffix(&mut self, n: usize) -> Self {
+    pub(crate) fn take_suffix(&mut self, n: usize) -> Self {
         let mid = if n <= self.len() {
             // SAFETY: We just checked that this will be between start and end,
             // and thus the subtraction cannot overflow.
diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs
index cd444c86ed0..3ba2957526f 100644
--- a/library/core/src/ops/try_trait.rs
+++ b/library/core/src/ops/try_trait.rs
@@ -338,6 +338,7 @@ pub trait FromResidual<R = <Self as Try>::Residual> {
 #[inline]
 #[track_caller] // because `Result::from_residual` has it
 #[lang = "from_yeet"]
+#[allow(unreachable_pub)] // not-exposed but still used via lang-item
 pub fn from_yeet<T, Y>(yeeted: Y) -> T
 where
     T: FromResidual<Yeet<Y>>,
@@ -383,12 +384,14 @@ impl<T> NeverShortCircuit<T> {
     /// This is useful for implementing infallible functions in terms of the `try_` ones,
     /// without accidentally capturing extra generic parameters in a closure.
     #[inline]
-    pub fn wrap_mut_1<A>(mut f: impl FnMut(A) -> T) -> impl FnMut(A) -> NeverShortCircuit<T> {
+    pub(crate) fn wrap_mut_1<A>(
+        mut f: impl FnMut(A) -> T,
+    ) -> impl FnMut(A) -> NeverShortCircuit<T> {
         move |a| NeverShortCircuit(f(a))
     }
 
     #[inline]
-    pub fn wrap_mut_2<A, B>(mut f: impl FnMut(A, B) -> T) -> impl FnMut(A, B) -> Self {
+    pub(crate) fn wrap_mut_2<A, B>(mut f: impl FnMut(A, B) -> T) -> impl FnMut(A, B) -> Self {
         move |a, b| NeverShortCircuit(f(a, b))
     }
 }
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 5a22110880c..ba5746d0ade 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -3071,19 +3071,21 @@ impl<T> [T] {
         sort::unstable::sort(self, &mut |a, b| f(a).lt(&f(b)));
     }
 
-    /// Reorders the slice such that the element at `index` after the reordering is at its final
-    /// sorted position.
+    /// Reorders the slice such that the element at `index` is at a sort-order position. All
+    /// elements before `index` will be `<=` to this value, and all elements after will be `>=` to
+    /// it.
     ///
-    /// This reordering has the additional property that any value at position `i < index` will be
-    /// less than or equal to any value at a position `j > index`. Additionally, this reordering is
-    /// unstable (i.e. any number of equal elements may end up at position `index`), in-place (i.e.
-    /// does not allocate), and runs in *O*(*n*) time. This function is also known as "kth element"
-    /// in other libraries.
+    /// This reordering is unstable (i.e. any element that compares equal to the nth element may end
+    /// up at that position), in-place (i.e.  does not allocate), and runs in *O*(*n*) time. This
+    /// function is also known as "kth element" in other libraries.
+    ///
+    /// Returns a triple that partitions the reordered slice:
+    ///
+    /// * The unsorted subslice before `index`, whose elements all satisfy `x <= self[index]`.
     ///
-    /// It returns a triplet of the following from the reordered slice: the subslice prior to
-    /// `index`, the element at `index`, and the subslice after `index`; accordingly, the values in
-    /// those two subslices will respectively all be less-than-or-equal-to and
-    /// greater-than-or-equal-to the value of the element at `index`.
+    /// * The element at `index`.
+    ///
+    /// * The unsorted subslice after `index`, whose elements all satisfy `x >= self[index]`.
     ///
     /// # Current implementation
     ///
@@ -3096,7 +3098,7 @@ impl<T> [T] {
     ///
     /// # Panics
     ///
-    /// Panics when `index >= len()`, meaning it always panics on empty slices.
+    /// Panics when `index >= len()`, and so always panics on empty slices.
     ///
     /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order].
     ///
@@ -3105,8 +3107,7 @@ impl<T> [T] {
     /// ```
     /// let mut v = [-5i32, 4, 2, -3, 1];
     ///
-    /// // Find the items less than or equal to the median, the median, and greater than or equal to
-    /// // the median.
+    /// // Find the items `<=` to the median, the median itself, and the items `>=` to it.
     /// let (lesser, median, greater) = v.select_nth_unstable(2);
     ///
     /// assert!(lesser == [-3, -5] || lesser == [-5, -3]);
@@ -3132,19 +3133,23 @@ impl<T> [T] {
         sort::select::partition_at_index(self, index, T::lt)
     }
 
-    /// Reorders the slice with a comparator function such that the element at `index` after the
-    /// reordering is at its final sorted position.
+    /// Reorders the slice with a comparator function such that the element at `index` is at a
+    /// sort-order position. All elements before `index` will be `<=` to this value, and all
+    /// elements after will be `>=` to it, according to the comparator function.
     ///
-    /// This reordering has the additional property that any value at position `i < index` will be
-    /// less than or equal to any value at a position `j > index` using the comparator function.
-    /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at
-    /// position `index`), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This
+    /// This reordering is unstable (i.e. any element that compares equal to the nth element may end
+    /// up at that position), in-place (i.e.  does not allocate), and runs in *O*(*n*) time. This
     /// function is also known as "kth element" in other libraries.
     ///
-    /// It returns a triplet of the following from the slice reordered according to the provided
-    /// comparator function: the subslice prior to `index`, the element at `index`, and the subslice
-    /// after `index`; accordingly, the values in those two subslices will respectively all be
-    /// less-than-or-equal-to and greater-than-or-equal-to the value of the element at `index`.
+    /// Returns a triple partitioning the reordered slice:
+    ///
+    /// * The unsorted subslice before `index`, whose elements all satisfy
+    ///   `compare(x, self[index]).is_le()`.
+    ///
+    /// * The element at `index`.
+    ///
+    /// * The unsorted subslice after `index`, whose elements all satisfy
+    ///   `compare(x, self[index]).is_ge()`.
     ///
     /// # Current implementation
     ///
@@ -3157,7 +3162,7 @@ impl<T> [T] {
     ///
     /// # Panics
     ///
-    /// Panics when `index >= len()`, meaning it always panics on empty slices.
+    /// Panics when `index >= len()`, and so always panics on empty slices.
     ///
     /// May panic if `compare` does not implement a [total order].
     ///
@@ -3166,13 +3171,13 @@ impl<T> [T] {
     /// ```
     /// let mut v = [-5i32, 4, 2, -3, 1];
     ///
-    /// // Find the items less than or equal to the median, the median, and greater than or equal to
-    /// // the median as if the slice were sorted in descending order.
-    /// let (lesser, median, greater) = v.select_nth_unstable_by(2, |a, b| b.cmp(a));
+    /// // Find the items `>=` to the median, the median itself, and the items `<=` to it, by using
+    /// // a reversed comparator.
+    /// let (before, median, after) = v.select_nth_unstable_by(2, |a, b| b.cmp(a));
     ///
-    /// assert!(lesser == [4, 2] || lesser == [2, 4]);
+    /// assert!(before == [4, 2] || before == [2, 4]);
     /// assert_eq!(median, &mut 1);
-    /// assert!(greater == [-3, -5] || greater == [-5, -3]);
+    /// assert!(after == [-3, -5] || after == [-5, -3]);
     ///
     /// // We are only guaranteed the slice will be one of the following, based on the way we sort
     /// // about the specified index.
@@ -3197,19 +3202,21 @@ impl<T> [T] {
         sort::select::partition_at_index(self, index, |a: &T, b: &T| compare(a, b) == Less)
     }
 
-    /// Reorders the slice with a key extraction function such that the element at `index` after the
-    /// reordering is at its final sorted position.
+    /// Reorders the slice with a key extraction function such that the element at `index` is at a
+    /// sort-order position. All elements before `index` will have keys `<=` to the key at `index`,
+    /// and all elements after will have keys `>=` to it.
     ///
-    /// This reordering has the additional property that any value at position `i < index` will be
-    /// less than or equal to any value at a position `j > index` using the key extraction function.
-    /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at
-    /// position `index`), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This
+    /// This reordering is unstable (i.e. any element that compares equal to the nth element may end
+    /// up at that position), in-place (i.e.  does not allocate), and runs in *O*(*n*) time. This
     /// function is also known as "kth element" in other libraries.
     ///
-    /// It returns a triplet of the following from the slice reordered according to the provided key
-    /// extraction function: the subslice prior to `index`, the element at `index`, and the subslice
-    /// after `index`; accordingly, the values in those two subslices will respectively all be
-    /// less-than-or-equal-to and greater-than-or-equal-to the value of the element at `index`.
+    /// Returns a triple partitioning the reordered slice:
+    ///
+    /// * The unsorted subslice before `index`, whose elements all satisfy `f(x) <= f(self[index])`.
+    ///
+    /// * The element at `index`.
+    ///
+    /// * The unsorted subslice after `index`, whose elements all satisfy `f(x) >= f(self[index])`.
     ///
     /// # Current implementation
     ///
@@ -3231,8 +3238,8 @@ impl<T> [T] {
     /// ```
     /// let mut v = [-5i32, 4, 1, -3, 2];
     ///
-    /// // Find the items less than or equal to the median, the median, and greater than or equal to
-    /// // the median as if the slice were sorted according to absolute value.
+    /// // Find the items `<=` to the absolute median, the absolute median itself, and the items
+    /// // `>=` to it.
     /// let (lesser, median, greater) = v.select_nth_unstable_by_key(2, |a| a.abs());
     ///
     /// assert!(lesser == [1, 2] || lesser == [2, 1]);
diff --git a/library/core/src/slice/rotate.rs b/library/core/src/slice/rotate.rs
index 1e4865a7caa..d8e0acb565c 100644
--- a/library/core/src/slice/rotate.rs
+++ b/library/core/src/slice/rotate.rs
@@ -60,7 +60,7 @@ use crate::{cmp, ptr};
 /// we cannot swap any more, but a smaller rotation problem is left to solve
 /// ```
 /// when `left < right` the swapping happens from the left instead.
-pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize) {
+pub(super) unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize) {
     type BufType = [usize; 32];
     if T::IS_ZST {
         return;
diff --git a/library/core/src/unicode/mod.rs b/library/core/src/unicode/mod.rs
index 6066aa99216..49dbdeb1a6d 100644
--- a/library/core/src/unicode/mod.rs
+++ b/library/core/src/unicode/mod.rs
@@ -17,6 +17,8 @@ pub(crate) use unicode_data::uppercase::lookup as Uppercase;
 pub(crate) use unicode_data::white_space::lookup as White_Space;
 
 pub(crate) mod printable;
+
+#[allow(unreachable_pub)]
 mod unicode_data;
 
 /// The version of [Unicode](https://www.unicode.org/) that the Unicode parts of
diff --git a/library/core/tests/bstr.rs b/library/core/tests/bstr.rs
new file mode 100644
index 00000000000..5fecd0a4084
--- /dev/null
+++ b/library/core/tests/bstr.rs
@@ -0,0 +1,54 @@
+#![feature(bstr)]
+
+use core::ByteStr;
+
+#[test]
+fn test_debug() {
+    assert_eq!(
+        r#""\0\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x11\x12\r\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x7f\x80\x81\xfe\xff""#,
+        format!("{:?}", ByteStr::new(b"\0\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x11\x12\r\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x7f\x80\x81\xfe\xff")),
+    );
+}
+
+#[test]
+fn test_display() {
+    let b1 = ByteStr::new("abc");
+    let b2 = ByteStr::new(b"\xf0\x28\x8c\xbc");
+
+    assert_eq!(&format!("{b1}"), "abc");
+    assert_eq!(&format!("{b2}"), "�(��");
+
+    assert_eq!(&format!("{b1:<7}!"), "abc    !");
+    assert_eq!(&format!("{b1:>7}!"), "    abc!");
+    assert_eq!(&format!("{b1:^7}!"), "  abc  !");
+    assert_eq!(&format!("{b1:^6}!"), " abc  !");
+    assert_eq!(&format!("{b1:-<7}!"), "abc----!");
+    assert_eq!(&format!("{b1:->7}!"), "----abc!");
+    assert_eq!(&format!("{b1:-^7}!"), "--abc--!");
+    assert_eq!(&format!("{b1:-^6}!"), "-abc--!");
+
+    assert_eq!(&format!("{b2:<7}!"), "�(��   !");
+    assert_eq!(&format!("{b2:>7}!"), "   �(��!");
+    assert_eq!(&format!("{b2:^7}!"), " �(��  !");
+    assert_eq!(&format!("{b2:^6}!"), " �(�� !");
+    assert_eq!(&format!("{b2:-<7}!"), "�(��---!");
+    assert_eq!(&format!("{b2:->7}!"), "---�(��!");
+    assert_eq!(&format!("{b2:-^7}!"), "-�(��--!");
+    assert_eq!(&format!("{b2:-^6}!"), "-�(��-!");
+
+    assert_eq!(&format!("{b1:<2}!"), "abc!");
+    assert_eq!(&format!("{b1:>2}!"), "abc!");
+    assert_eq!(&format!("{b1:^2}!"), "abc!");
+    assert_eq!(&format!("{b1:-<2}!"), "abc!");
+    assert_eq!(&format!("{b1:->2}!"), "abc!");
+    assert_eq!(&format!("{b1:-^2}!"), "abc!");
+
+    assert_eq!(&format!("{b2:<3}!"), "�(��!");
+    assert_eq!(&format!("{b2:>3}!"), "�(��!");
+    assert_eq!(&format!("{b2:^3}!"), "�(��!");
+    assert_eq!(&format!("{b2:^2}!"), "�(��!");
+    assert_eq!(&format!("{b2:-<3}!"), "�(��!");
+    assert_eq!(&format!("{b2:->3}!"), "�(��!");
+    assert_eq!(&format!("{b2:-^3}!"), "�(��!");
+    assert_eq!(&format!("{b2:-^2}!"), "�(��!");
+}
diff --git a/library/core/tests/net/ip_addr.rs b/library/core/tests/net/ip_addr.rs
index 707f9a160e1..f01b43282ec 100644
--- a/library/core/tests/net/ip_addr.rs
+++ b/library/core/tests/net/ip_addr.rs
@@ -332,6 +332,7 @@ fn ip_properties() {
     check!("ff08::", global | multicast);
     check!("ff0e::", global | multicast);
     check!("2001:db8:85a3::8a2e:370:7334", doc);
+    check!("3fff:fff:ffff:ffff:ffff:ffff:ffff:ffff", doc);
     check!("2001:2::ac32:23ff:21", benchmarking);
     check!("102:304:506:708:90a:b0c:d0e:f10", global);
 }
@@ -791,6 +792,15 @@ fn ipv6_properties() {
     );
 
     check!(
+        "3fff:fff:ffff:ffff:ffff:ffff:ffff:ffff",
+        &[
+            0x3f, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+            0xff, 0xff
+        ],
+        documentation
+    );
+
+    check!(
         "2001:2::ac32:23ff:21",
         &[0x20, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0xac, 0x32, 0x23, 0xff, 0, 0x21],
         benchmarking
diff --git a/library/panic_unwind/src/dummy.rs b/library/panic_unwind/src/dummy.rs
index a4bcd216c60..a0d68766918 100644
--- a/library/panic_unwind/src/dummy.rs
+++ b/library/panic_unwind/src/dummy.rs
@@ -6,10 +6,10 @@ use alloc::boxed::Box;
 use core::any::Any;
 use core::intrinsics;
 
-pub unsafe fn cleanup(_ptr: *mut u8) -> Box<dyn Any + Send> {
+pub(crate) unsafe fn cleanup(_ptr: *mut u8) -> Box<dyn Any + Send> {
     intrinsics::abort()
 }
 
-pub unsafe fn panic(_data: Box<dyn Any + Send>) -> u32 {
+pub(crate) unsafe fn panic(_data: Box<dyn Any + Send>) -> u32 {
     intrinsics::abort()
 }
diff --git a/library/panic_unwind/src/emcc.rs b/library/panic_unwind/src/emcc.rs
index b986fc1c2a8..9127449edb1 100644
--- a/library/panic_unwind/src/emcc.rs
+++ b/library/panic_unwind/src/emcc.rs
@@ -64,7 +64,7 @@ struct Exception {
     data: Option<Box<dyn Any + Send>>,
 }
 
-pub unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
+pub(crate) unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
     // intrinsics::try actually gives us a pointer to this structure.
     #[repr(C)]
     struct CatchData {
@@ -93,7 +93,7 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
     out
 }
 
-pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
+pub(crate) unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
     let exception = __cxa_allocate_exception(mem::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/gcc.rs b/library/panic_unwind/src/gcc.rs
index b2389078afd..e478f6c5fc8 100644
--- a/library/panic_unwind/src/gcc.rs
+++ b/library/panic_unwind/src/gcc.rs
@@ -58,7 +58,7 @@ struct Exception {
     cause: Box<dyn Any + Send>,
 }
 
-pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
+pub(crate) unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
     let exception = Box::new(Exception {
         _uwe: uw::_Unwind_Exception {
             exception_class: RUST_EXCEPTION_CLASS,
@@ -82,7 +82,7 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
     }
 }
 
-pub unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
+pub(crate) unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
     let exception = ptr as *mut uw::_Unwind_Exception;
     if (*exception).exception_class != RUST_EXCEPTION_CLASS {
         uw::_Unwind_DeleteException(exception);
diff --git a/library/panic_unwind/src/hermit.rs b/library/panic_unwind/src/hermit.rs
index 69b9edb77c5..8ac827dd9cc 100644
--- a/library/panic_unwind/src/hermit.rs
+++ b/library/panic_unwind/src/hermit.rs
@@ -5,14 +5,14 @@
 use alloc::boxed::Box;
 use core::any::Any;
 
-pub unsafe fn cleanup(_ptr: *mut u8) -> Box<dyn Any + Send> {
+pub(crate) unsafe fn cleanup(_ptr: *mut u8) -> Box<dyn Any + Send> {
     extern "C" {
         pub fn __rust_abort() -> !;
     }
     __rust_abort();
 }
 
-pub unsafe fn panic(_data: Box<dyn Any + Send>) -> u32 {
+pub(crate) unsafe fn panic(_data: Box<dyn Any + Send>) -> u32 {
     extern "C" {
         pub fn __rust_abort() -> !;
     }
diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs
index dc78be76cb4..d6828164195 100644
--- a/library/panic_unwind/src/lib.rs
+++ b/library/panic_unwind/src/lib.rs
@@ -26,6 +26,7 @@
 #![cfg_attr(miri, allow(dead_code))]
 #![allow(internal_features)]
 #![cfg_attr(not(bootstrap), feature(cfg_emscripten_wasm_eh))]
+#![warn(unreachable_pub)]
 
 use alloc::boxed::Box;
 use core::any::Any;
diff --git a/library/panic_unwind/src/miri.rs b/library/panic_unwind/src/miri.rs
index 695adadd59b..a86f0e91eef 100644
--- a/library/panic_unwind/src/miri.rs
+++ b/library/panic_unwind/src/miri.rs
@@ -12,14 +12,14 @@ extern "Rust" {
     fn miri_start_unwind(payload: *mut u8) -> !;
 }
 
-pub unsafe fn panic(payload: Box<dyn Any + Send>) -> u32 {
+pub(crate) unsafe fn panic(payload: Box<dyn Any + Send>) -> u32 {
     // The payload we pass to `miri_start_unwind` will be exactly the argument we get
     // in `cleanup` below. So we just box it up once, to get something pointer-sized.
     let payload_box: Payload = Box::new(payload);
     miri_start_unwind(Box::into_raw(payload_box) as *mut u8)
 }
 
-pub unsafe fn cleanup(payload_box: *mut u8) -> Box<dyn Any + Send> {
+pub(crate) unsafe fn cleanup(payload_box: *mut u8) -> Box<dyn Any + Send> {
     // Recover the underlying `Box`.
     let payload_box: Payload = Box::from_raw(payload_box as *mut _);
     *payload_box
diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs
index 5afa0a19756..21bfe74e1a2 100644
--- a/library/panic_unwind/src/seh.rs
+++ b/library/panic_unwind/src/seh.rs
@@ -111,18 +111,18 @@ struct Exception {
 mod imp {
     #[repr(transparent)]
     #[derive(Copy, Clone)]
-    pub struct ptr_t(*mut u8);
+    pub(super) struct ptr_t(*mut u8);
 
     impl ptr_t {
-        pub const fn null() -> Self {
+        pub(super) const fn null() -> Self {
             Self(core::ptr::null_mut())
         }
 
-        pub const fn new(ptr: *mut u8) -> Self {
+        pub(super) const fn new(ptr: *mut u8) -> Self {
             Self(ptr)
         }
 
-        pub const fn raw(self) -> *mut u8 {
+        pub(super) const fn raw(self) -> *mut u8 {
             self.0
         }
     }
@@ -133,18 +133,18 @@ mod imp {
     // On 64-bit systems, SEH represents pointers as 32-bit offsets from `__ImageBase`.
     #[repr(transparent)]
     #[derive(Copy, Clone)]
-    pub struct ptr_t(u32);
+    pub(super) struct ptr_t(u32);
 
     extern "C" {
-        pub static __ImageBase: u8;
+        static __ImageBase: u8;
     }
 
     impl ptr_t {
-        pub const fn null() -> Self {
+        pub(super) const fn null() -> Self {
             Self(0)
         }
 
-        pub fn new(ptr: *mut u8) -> Self {
+        pub(super) fn new(ptr: *mut u8) -> Self {
             // We need to expose the provenance of the pointer because it is not carried by
             // the `u32`, while the FFI needs to have this provenance to excess our statics.
             //
@@ -159,7 +159,7 @@ mod imp {
             Self(offset as u32)
         }
 
-        pub const fn raw(self) -> u32 {
+        pub(super) const fn raw(self) -> u32 {
             self.0
         }
     }
@@ -168,7 +168,7 @@ mod imp {
 use imp::ptr_t;
 
 #[repr(C)]
-pub struct _ThrowInfo {
+struct _ThrowInfo {
     pub attributes: c_uint,
     pub pmfnUnwind: ptr_t,
     pub pForwardCompat: ptr_t,
@@ -176,13 +176,13 @@ pub struct _ThrowInfo {
 }
 
 #[repr(C)]
-pub struct _CatchableTypeArray {
+struct _CatchableTypeArray {
     pub nCatchableTypes: c_int,
     pub arrayOfCatchableTypes: [ptr_t; 1],
 }
 
 #[repr(C)]
-pub struct _CatchableType {
+struct _CatchableType {
     pub properties: c_uint,
     pub pType: ptr_t,
     pub thisDisplacement: _PMD,
@@ -191,14 +191,14 @@ pub struct _CatchableType {
 }
 
 #[repr(C)]
-pub struct _PMD {
+struct _PMD {
     pub mdisp: c_int,
     pub pdisp: c_int,
     pub vdisp: c_int,
 }
 
 #[repr(C)]
-pub struct _TypeDescriptor {
+struct _TypeDescriptor {
     pub pVFTable: *const u8,
     pub spare: *mut u8,
     pub name: [u8; 11],
@@ -288,7 +288,7 @@ cfg_if::cfg_if! {
    }
 }
 
-pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
+pub(crate) unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
     use core::intrinsics::atomic_store_seqcst;
 
     // _CxxThrowException executes entirely on this stack frame, so there's no
@@ -350,7 +350,7 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
     _CxxThrowException(throw_ptr, (&raw mut THROW_INFO) as *mut _);
 }
 
-pub unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send> {
+pub(crate) unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send> {
     // A null payload here means that we got here from the catch (...) of
     // __rust_try. This happens when a non-Rust foreign exception is caught.
     if payload.is_null() {
diff --git a/library/rtstartup/rsbegin.rs b/library/rtstartup/rsbegin.rs
index 9a3d95bd8dd..d3ff5c14aa4 100644
--- a/library/rtstartup/rsbegin.rs
+++ b/library/rtstartup/rsbegin.rs
@@ -19,6 +19,7 @@
 #![no_core]
 #![allow(non_camel_case_types)]
 #![allow(internal_features)]
+#![warn(unreachable_pub)]
 
 #[lang = "sized"]
 trait Sized {}
diff --git a/library/rtstartup/rsend.rs b/library/rtstartup/rsend.rs
index 2514eb00344..81acfbed447 100644
--- a/library/rtstartup/rsend.rs
+++ b/library/rtstartup/rsend.rs
@@ -6,6 +6,7 @@
 #![crate_type = "rlib"]
 #![no_core]
 #![allow(internal_features)]
+#![warn(unreachable_pub)]
 
 #[lang = "sized"]
 trait Sized {}
diff --git a/library/std/src/bstr.rs b/library/std/src/bstr.rs
new file mode 100644
index 00000000000..dd491771628
--- /dev/null
+++ b/library/std/src/bstr.rs
@@ -0,0 +1,4 @@
+//! The `ByteStr` and `ByteString` types and trait implementations.
+
+#[unstable(feature = "bstr", issue = "134915")]
+pub use alloc::bstr::{ByteStr, ByteString};
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index 11a29cdae62..bbd506127fb 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -336,7 +336,10 @@ impl Error for VarError {
 ///  - [Austin Group Bugzilla](https://austingroupbugs.net/view.php?id=188)
 ///  - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2)
 ///
+/// To pass an environment variable to a child process, you can instead use [`Command::env`].
+///
 /// [`std::net::ToSocketAddrs`]: crate::net::ToSocketAddrs
+/// [`Command::env`]: crate::process::Command::env
 ///
 /// # Panics
 ///
@@ -396,7 +399,12 @@ pub unsafe fn set_var<K: AsRef<OsStr>, V: AsRef<OsStr>>(key: K, value: V) {
 ///  - [Austin Group Bugzilla](https://austingroupbugs.net/view.php?id=188)
 ///  - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2)
 ///
+/// To prevent a child process from inheriting an environment variable, you can
+/// instead use [`Command::env_remove`] or [`Command::env_clear`].
+///
 /// [`std::net::ToSocketAddrs`]: crate::net::ToSocketAddrs
+/// [`Command::env_remove`]: crate::process::Command::env_remove
+/// [`Command::env_clear`]: crate::process::Command::env_clear
 ///
 /// # Panics
 ///
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index 7fb57d41043..c4c8dbccd7a 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -203,8 +203,8 @@ impl OsString {
         self
     }
 
-    /// Converts the `OsString` into a byte slice.  To convert the byte slice back into an
-    /// `OsString`, use the [`OsStr::from_encoded_bytes_unchecked`] function.
+    /// Converts the `OsString` into a byte vector.  To convert the byte vector back into an
+    /// `OsString`, use the [`OsString::from_encoded_bytes_unchecked`] function.
     ///
     /// The byte encoding is an unspecified, platform-specific, self-synchronizing superset of UTF-8.
     /// By being a self-synchronizing superset of UTF-8, this encoding is also a superset of 7-bit
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index 0c526eafdf3..1d26bf37f4d 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -2387,13 +2387,12 @@ mod async_keyword {}
 /// [`async`]: ../std/keyword.async.html
 mod await_keyword {}
 
-// FIXME(dyn_compat_renaming): Update URL and link text.
 #[doc(keyword = "dyn")]
 //
 /// `dyn` is a prefix of a [trait object]'s type.
 ///
 /// The `dyn` keyword is used to highlight that calls to methods on the associated `Trait`
-/// are [dynamically dispatched]. To use the trait this way, it must be 'dyn-compatible'[^1].
+/// are [dynamically dispatched]. To use the trait this way, it must be *dyn compatible*[^1].
 ///
 /// Unlike generic parameters or `impl Trait`, the compiler does not know the concrete type that
 /// is being passed. That is, the type has been [erased].
@@ -2406,7 +2405,7 @@ mod await_keyword {}
 /// the function pointer and then that function pointer is called.
 ///
 /// See the Reference for more information on [trait objects][ref-trait-obj]
-/// and [object safety][ref-obj-safety].
+/// and [dyn compatibility][ref-dyn-compat].
 ///
 /// ## Trade-offs
 ///
@@ -2419,9 +2418,9 @@ mod await_keyword {}
 /// [trait object]: ../book/ch17-02-trait-objects.html
 /// [dynamically dispatched]: https://en.wikipedia.org/wiki/Dynamic_dispatch
 /// [ref-trait-obj]: ../reference/types/trait-object.html
-/// [ref-obj-safety]: ../reference/items/traits.html#object-safety
+/// [ref-dyn-compat]: ../reference/items/traits.html#dyn-compatibility
 /// [erased]: https://en.wikipedia.org/wiki/Type_erasure
-/// [^1]: Formerly known as 'object safe'.
+/// [^1]: Formerly known as *object safe*.
 mod dyn_keyword {}
 
 #[doc(keyword = "union")]
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 39f234e4ba6..acb3a0578e5 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -320,6 +320,8 @@
 // Library features (core):
 // tidy-alphabetical-start
 #![feature(array_chunks)]
+#![feature(bstr)]
+#![feature(bstr_internals)]
 #![feature(c_str_module)]
 #![feature(char_internals)]
 #![feature(clone_to_uninit)]
@@ -581,6 +583,8 @@ pub mod f64;
 pub mod thread;
 pub mod ascii;
 pub mod backtrace;
+#[unstable(feature = "bstr", issue = "134915")]
+pub mod bstr;
 pub mod collections;
 pub mod env;
 pub mod error;
diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs
index 22f5528248a..03dff94350d 100644
--- a/library/std/src/os/fd/raw.rs
+++ b/library/std/src/os/fd/raw.rs
@@ -19,11 +19,9 @@ use crate::sys_common::{AsInner, IntoInner};
 use crate::{fs, io};
 
 /// Raw file descriptors.
-#[rustc_allowed_through_unstable_modules]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg(not(target_os = "hermit"))]
 pub type RawFd = raw::c_int;
-#[rustc_allowed_through_unstable_modules]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg(target_os = "hermit")]
 pub type RawFd = i32;
@@ -33,7 +31,6 @@ pub type RawFd = i32;
 /// This is only available on unix and WASI platforms and must be imported in
 /// order to call the method. Windows platforms have a corresponding
 /// `AsRawHandle` and `AsRawSocket` set of traits.
-#[rustc_allowed_through_unstable_modules]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait AsRawFd {
     /// Extracts the raw file descriptor.
@@ -67,7 +64,6 @@ pub trait AsRawFd {
 
 /// A trait to express the ability to construct an object from a raw file
 /// descriptor.
-#[rustc_allowed_through_unstable_modules]
 #[stable(feature = "from_raw_os", since = "1.1.0")]
 pub trait FromRawFd {
     /// Constructs a new instance of `Self` from the given raw file
@@ -112,7 +108,6 @@ pub trait FromRawFd {
 
 /// A trait to express the ability to consume an object and acquire ownership of
 /// its raw file descriptor.
-#[rustc_allowed_through_unstable_modules]
 #[stable(feature = "into_raw_os", since = "1.4.0")]
 pub trait IntoRawFd {
     /// Consumes this object, returning the raw underlying file descriptor.
diff --git a/library/std/src/os/wasi/io/fd.rs b/library/std/src/os/wasi/io/fd.rs
deleted file mode 100644
index 930aca887e3..00000000000
--- a/library/std/src/os/wasi/io/fd.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//! Owned and borrowed file descriptors.
-
-#![unstable(feature = "wasi_ext", issue = "71213")]
-
-// Tests for this module
-#[cfg(test)]
-mod tests;
-
-pub use crate::os::fd::owned::*;
diff --git a/library/std/src/os/wasi/io/mod.rs b/library/std/src/os/wasi/io/mod.rs
index 4e123a1eec8..5f9a735db08 100644
--- a/library/std/src/os/wasi/io/mod.rs
+++ b/library/std/src/os/wasi/io/mod.rs
@@ -4,3 +4,7 @@
 
 #[stable(feature = "io_safety_wasi", since = "1.65.0")]
 pub use crate::os::fd::*;
+
+// Tests for this module
+#[cfg(test)]
+mod tests;
diff --git a/library/std/src/os/wasi/io/raw.rs b/library/std/src/os/wasi/io/raw.rs
deleted file mode 100644
index da3b36adad4..00000000000
--- a/library/std/src/os/wasi/io/raw.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-//! WASI-specific extensions to general I/O primitives.
-
-#![unstable(feature = "wasi_ext", issue = "71213")]
-
-// NOTE: despite the fact that this module is unstable,
-// stable Rust had the capability to access the stable
-// re-exported items from os::fd::raw through this
-// unstable module.
-// In PR #95956 the stability checker was changed to check
-// all path segments of an item rather than just the last,
-// which caused the aforementioned stable usage to regress
-// (see issue #99502).
-// As a result, the items in os::fd::raw were given the
-// rustc_allowed_through_unstable_modules attribute.
-// No regression tests were added to ensure this property,
-// as CI is not configured to test wasm32-wasi.
-// If this module is stabilized,
-// you may want to remove those attributes
-// (assuming no other unstable modules need them).
-pub use crate::os::fd::raw::*;
diff --git a/library/std/src/os/wasi/io/fd/tests.rs b/library/std/src/os/wasi/io/tests.rs
index 418274752b0..418274752b0 100644
--- a/library/std/src/os/wasi/io/fd/tests.rs
+++ b/library/std/src/os/wasi/io/tests.rs
diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs
index 384369b0012..3a22a16cb16 100644
--- a/library/std/src/rt.rs
+++ b/library/std/src/rt.rs
@@ -32,9 +32,14 @@ use crate::{mem, panic, sys};
 // - nothing (so this macro is a no-op)
 macro_rules! rtprintpanic {
     ($($t:tt)*) => {
+        #[cfg(not(feature = "panic_immediate_abort"))]
         if let Some(mut out) = crate::sys::stdio::panic_output() {
             let _ = crate::io::Write::write_fmt(&mut out, format_args!($($t)*));
         }
+        #[cfg(feature = "panic_immediate_abort")]
+        {
+            let _ = format_args!($($t)*);
+        }
     }
 }
 
diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs
index b3659351b8c..f8493c21ad4 100644
--- a/library/std/src/sys/pal/windows/fs.rs
+++ b/library/std/src/sys/pal/windows/fs.rs
@@ -328,9 +328,6 @@ impl File {
                         mem::size_of::<c::FILE_ALLOCATION_INFO>() as u32,
                     );
                     if result == 0 {
-                        if api::get_last_error().code != 0 {
-                            panic!("FILE_ALLOCATION_INFO failed!!!");
-                        }
                         let eof = c::FILE_END_OF_FILE_INFO { EndOfFile: 0 };
                         let result = c::SetFileInformationByHandle(
                             handle.as_raw_handle(),
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index 2313f4b5beb..c003503ca8b 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -230,6 +230,14 @@ impl fmt::Display for AccessError {
 #[stable(feature = "thread_local_try_with", since = "1.26.0")]
 impl Error for AccessError {}
 
+// This ensures the panicking code is outlined from `with` for `LocalKey`.
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[track_caller]
+#[cold]
+fn panic_access_error(err: AccessError) -> ! {
+    panic!("cannot access a Thread Local Storage value during or after destruction: {err:?}")
+}
+
 impl<T: 'static> LocalKey<T> {
     #[doc(hidden)]
     #[unstable(
@@ -269,10 +277,10 @@ impl<T: 'static> LocalKey<T> {
     where
         F: FnOnce(&T) -> R,
     {
-        self.try_with(f).expect(
-            "cannot access a Thread Local Storage value \
-             during or after destruction",
-        )
+        match self.try_with(f) {
+            Ok(r) => r,
+            Err(err) => panic_access_error(err),
+        }
     }
 
     /// Acquires a reference to the value in this TLS key.
@@ -327,10 +335,10 @@ impl<T: 'static> LocalKey<T> {
         let mut init = Some(init);
 
         let reference = unsafe {
-            (self.inner)(Some(&mut init)).as_ref().expect(
-                "cannot access a Thread Local Storage value \
-                 during or after destruction",
-            )
+            match (self.inner)(Some(&mut init)).as_ref() {
+                Some(r) => r,
+                None => panic_access_error(AccessError),
+            }
         };
 
         f(init, reference)
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index c46aae2ded1..d2f3c7f36ca 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -62,7 +62,7 @@ dependencies = [
  "tracing-subscriber",
  "tracing-tree",
  "walkdir",
- "windows 0.52.0",
+ "windows",
  "xz2",
 ]
 
@@ -663,7 +663,7 @@ dependencies = [
  "libc",
  "memchr",
  "ntapi",
- "windows 0.57.0",
+ "windows",
 ]
 
 [[package]]
@@ -845,30 +845,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
 name = "windows"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
-dependencies = [
- "windows-core 0.52.0",
- "windows-targets",
-]
-
-[[package]]
-name = "windows"
 version = "0.57.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
 dependencies = [
- "windows-core 0.57.0",
- "windows-targets",
-]
-
-[[package]]
-name = "windows-core"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
-dependencies = [
+ "windows-core",
  "windows-targets",
 ]
 
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index 71c56c4e85e..d7afcc7f27d 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -74,7 +74,7 @@ tracing-tree = { version = "0.4.0", optional = true }
 version = "1.0.0"
 
 [target.'cfg(windows)'.dependencies.windows]
-version = "0.52"
+version = "0.57"
 features = [
     "Win32_Foundation",
     "Win32_Security",
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 76ee40c6f45..74923af1555 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -1268,6 +1268,11 @@ def bootstrap(args):
         config_toml = ""
 
     profile = RustBuild.get_toml_static(config_toml, "profile")
+    is_non_git_source = not os.path.exists(os.path.join(rust_root, ".git"))
+
+    if profile is None and is_non_git_source:
+        profile = "dist"
+
     if profile is not None:
         # Allows creating alias for profile names, allowing
         # profiles to be renamed while maintaining back compatibility
diff --git a/src/bootstrap/defaults/config.compiler.toml b/src/bootstrap/defaults/config.compiler.toml
index a737de3bd08..269b90106e3 100644
--- a/src/bootstrap/defaults/config.compiler.toml
+++ b/src/bootstrap/defaults/config.compiler.toml
@@ -8,6 +8,8 @@ compiler-docs = true
 # where adding `debug!()` appears to do nothing.
 # However, it makes running the compiler slightly slower.
 debug-logging = true
+# Enables debug assertions, which guard from many mistakes when working on the compiler.
+debug-assertions = true
 # Get actually-useful information from backtraces, profiling, etc. with minimal added bytes
 debuginfo-level = "line-tables-only"
 # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in
index a1f38b9ac14..275c0e803cb 100644
--- a/src/bootstrap/mk/Makefile.in
+++ b/src/bootstrap/mk/Makefile.in
@@ -97,13 +97,18 @@ tidy:
 prepare:
 	$(Q)$(BOOTSTRAP) build --stage 2 --dry-run
 
+# Set of tests that represent around half of the time of the test suite.
+# Used to split tests across multiple CI runners.
+STAGE_2_TEST_SET1 := test --stage 2 --skip=compiler --skip=src
+STAGE_2_TEST_SET2 := test --stage 2 --skip=tests --skip=coverage-map --skip=coverage-run --skip=library --skip=tidyselftest
+
 ## MSVC native builders
 
 # this intentionally doesn't use `$(BOOTSTRAP)` so we can test the shebang on Windows
 ci-msvc-py:
-	$(Q)$(CFG_SRC_DIR)/x.py test --stage 2 tidy
+	$(Q)$(CFG_SRC_DIR)/x.py $(STAGE_2_TEST_SET1)
 ci-msvc-ps1:
-	$(Q)$(CFG_SRC_DIR)/x.ps1 test --stage 2 --skip tidy
+	$(Q)$(CFG_SRC_DIR)/x.ps1 $(STAGE_2_TEST_SET2)
 ci-msvc: ci-msvc-py ci-msvc-ps1
 
 ## MingW native builders
@@ -112,9 +117,9 @@ ci-msvc: ci-msvc-py ci-msvc-ps1
 # Used to split tests across multiple CI runners.
 # Test both x and bootstrap entrypoints.
 ci-mingw-x:
-	$(Q)$(CFG_SRC_DIR)/x test --stage 2 --skip=compiler --skip=src
+	$(Q)$(CFG_SRC_DIR)/x $(STAGE_2_TEST_SET1)
 ci-mingw-bootstrap:
-	$(Q)$(BOOTSTRAP) test --stage 2 --skip=tests --skip=coverage-map --skip=coverage-run --skip=library --skip=tidyselftest
+	$(Q)$(BOOTSTRAP) $(STAGE_2_TEST_SET2)
 ci-mingw: ci-mingw-x ci-mingw-bootstrap
 
 .PHONY: dist
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 470e400243f..18f920b85ee 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -1015,7 +1015,18 @@ impl Step for PlainSourceTarball {
         ];
         let src_dirs = ["src", "compiler", "library", "tests", "LICENSES"];
 
-        copy_src_dirs(builder, &builder.src, &src_dirs, &[], plain_dst_src);
+        copy_src_dirs(
+            builder,
+            &builder.src,
+            &src_dirs,
+            &[
+                // We don't currently use the GCC source code for building any official components,
+                // it is very big, and has unclear licensing implications due to being GPL licensed.
+                // We thus exclude it from the source tarball from now.
+                "src/gcc",
+            ],
+            plain_dst_src,
+        );
 
         // Copy the files normally
         for item in &src_files {
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index cf55fff4078..3cf25373b89 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -1338,7 +1338,7 @@ impl Step for CrtBeginEnd {
             .file(crtbegin_src)
             .file(crtend_src);
 
-        // Those flags are defined in src/llvm-project/compiler-rt/lib/crt/CMakeLists.txt
+        // Those flags are defined in src/llvm-project/compiler-rt/lib/builtins/CMakeLists.txt
         // Currently only consumer of those objects is musl, which use .init_array/.fini_array
         // instead of .ctors/.dtors
         cfg.flag("-std=c11")
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 9f3e4d9cc89..0d3ab6ad97d 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -87,7 +87,7 @@ impl Step for CrateBootstrap {
             &[],
         );
         let crate_name = path.rsplit_once('/').unwrap().1;
-        run_cargo_test(cargo, &[], &[], crate_name, crate_name, compiler, bootstrap_host, builder);
+        run_cargo_test(cargo, &[], &[], crate_name, crate_name, bootstrap_host, builder);
     }
 }
 
@@ -143,7 +143,6 @@ You can skip linkcheck with --skip src/tools/linkchecker"
             &[],
             "linkchecker",
             "linkchecker self tests",
-            compiler,
             bootstrap_host,
             builder,
         );
@@ -312,7 +311,7 @@ impl Step for Cargo {
         );
 
         // NOTE: can't use `run_cargo_test` because we need to overwrite `PATH`
-        let mut cargo = prepare_cargo_test(cargo, &[], &[], "cargo", compiler, self.host, builder);
+        let mut cargo = prepare_cargo_test(cargo, &[], &[], "cargo", self.host, builder);
 
         // Don't run cross-compile tests, we may not have cross-compiled libstd libs
         // available.
@@ -397,7 +396,7 @@ impl Step for RustAnalyzer {
         cargo.env("SKIP_SLOW_TESTS", "1");
 
         cargo.add_rustc_lib_path(builder);
-        run_cargo_test(cargo, &[], &[], "rust-analyzer", "rust-analyzer", compiler, host, builder);
+        run_cargo_test(cargo, &[], &[], "rust-analyzer", "rust-analyzer", host, builder);
     }
 }
 
@@ -445,7 +444,7 @@ impl Step for Rustfmt {
 
         cargo.add_rustc_lib_path(builder);
 
-        run_cargo_test(cargo, &[], &[], "rustfmt", "rustfmt", compiler, host, builder);
+        run_cargo_test(cargo, &[], &[], "rustfmt", "rustfmt", host, builder);
     }
 }
 
@@ -565,7 +564,7 @@ impl Step for Miri {
 
         // We can NOT use `run_cargo_test` since Miri's integration tests do not use the usual test
         // harness and therefore do not understand the flags added by `add_flags_and_try_run_test`.
-        let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", host_compiler, host, builder);
+        let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", host, builder);
 
         // miri tests need to know about the stage sysroot
         cargo.env("MIRI_SYSROOT", &miri_sysroot);
@@ -713,16 +712,7 @@ impl Step for CompiletestTest {
             &[],
         );
         cargo.allow_features("test");
-        run_cargo_test(
-            cargo,
-            &[],
-            &[],
-            "compiletest",
-            "compiletest self test",
-            compiler,
-            host,
-            builder,
-        );
+        run_cargo_test(cargo, &[], &[], "compiletest", "compiletest self test", host, builder);
     }
 }
 
@@ -769,7 +759,7 @@ impl Step for Clippy {
         cargo.env("HOST_LIBS", host_libs);
 
         cargo.add_rustc_lib_path(builder);
-        let cargo = prepare_cargo_test(cargo, &[], &[], "clippy", compiler, host, builder);
+        let cargo = prepare_cargo_test(cargo, &[], &[], "clippy", host, builder);
 
         let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "clippy", host, host);
 
@@ -1294,7 +1284,6 @@ impl Step for CrateRunMakeSupport {
             &[],
             "run-make-support",
             "run-make-support self test",
-            compiler,
             host,
             builder,
         );
@@ -1334,16 +1323,7 @@ impl Step for CrateBuildHelper {
             &[],
         );
         cargo.allow_features("test");
-        run_cargo_test(
-            cargo,
-            &[],
-            &[],
-            "build_helper",
-            "build_helper self test",
-            compiler,
-            host,
-            builder,
-        );
+        run_cargo_test(cargo, &[], &[], "build_helper", "build_helper self test", host, builder);
     }
 }
 
@@ -2540,19 +2520,17 @@ impl Step for CrateLibrustc {
 /// Given a `cargo test` subcommand, add the appropriate flags and run it.
 ///
 /// Returns whether the test succeeded.
-#[allow(clippy::too_many_arguments)] // FIXME: reduce the number of args and remove this.
 fn run_cargo_test<'a>(
-    cargo: impl Into<BootstrapCommand>,
+    cargo: builder::Cargo,
     libtest_args: &[&str],
     crates: &[String],
     primary_crate: &str,
     description: impl Into<Option<&'a str>>,
-    compiler: Compiler,
     target: TargetSelection,
     builder: &Builder<'_>,
 ) -> bool {
-    let mut cargo =
-        prepare_cargo_test(cargo, libtest_args, crates, primary_crate, compiler, target, builder);
+    let compiler = cargo.compiler();
+    let mut cargo = prepare_cargo_test(cargo, libtest_args, crates, primary_crate, target, builder);
     let _time = helpers::timeit(builder);
     let _group = description.into().and_then(|what| {
         builder.msg_sysroot_tool(Kind::Test, compiler.stage, what, compiler.host, target)
@@ -2573,15 +2551,15 @@ fn run_cargo_test<'a>(
 
 /// Given a `cargo test` subcommand, pass it the appropriate test flags given a `builder`.
 fn prepare_cargo_test(
-    cargo: impl Into<BootstrapCommand>,
+    cargo: builder::Cargo,
     libtest_args: &[&str],
     crates: &[String],
     primary_crate: &str,
-    compiler: Compiler,
     target: TargetSelection,
     builder: &Builder<'_>,
 ) -> BootstrapCommand {
-    let mut cargo = cargo.into();
+    let compiler = cargo.compiler();
+    let mut cargo: BootstrapCommand = cargo.into();
 
     // Propagate `--bless` if it has not already been set/unset
     // Any tools that want to use this should bless if `RUSTC_BLESS` is set to
@@ -2793,7 +2771,6 @@ impl Step for Crate {
             &self.crates,
             &self.crates[0],
             &*crate_description(&self.crates),
-            compiler,
             target,
             builder,
         );
@@ -2895,7 +2872,6 @@ impl Step for CrateRustdoc {
             &["rustdoc:0.0.0".to_string()],
             "rustdoc",
             "rustdoc",
-            compiler,
             target,
             builder,
         );
@@ -2956,7 +2932,6 @@ impl Step for CrateRustdocJsonTypes {
             &["rustdoc-json-types".to_string()],
             "rustdoc-json-types",
             "rustdoc-json-types",
-            compiler,
             target,
             builder,
         );
@@ -3113,23 +3088,25 @@ impl Step for Bootstrap {
         // Use `python -m unittest` manually if you want to pass arguments.
         check_bootstrap.delay_failure().run(builder);
 
-        let mut cmd = command(&builder.initial_cargo);
-        cmd.arg("test")
-            .current_dir(builder.src.join("src/bootstrap"))
-            .env("RUSTFLAGS", "--cfg test -Cdebuginfo=2")
+        let mut cargo = tool::prepare_tool_cargo(
+            builder,
+            compiler,
+            Mode::ToolBootstrap,
+            host,
+            Kind::Test,
+            "src/bootstrap",
+            SourceType::InTree,
+            &[],
+        );
+
+        cargo
+            .rustflag("-Cdebuginfo=2")
             .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
-            .env("RUSTC_BOOTSTRAP", "1")
-            .env("RUSTDOC", builder.rustdoc(compiler))
-            .env("RUSTC", &builder.initial_rustc);
-        if let Some(flags) = option_env!("RUSTFLAGS") {
-            // Use the same rustc flags for testing as for "normal" compilation,
-            // so that Cargo doesn’t recompile the entire dependency graph every time:
-            // https://github.com/rust-lang/rust/issues/49215
-            cmd.env("RUSTFLAGS", flags);
-        }
+            .env("RUSTC_BOOTSTRAP", "1");
+
         // bootstrap tests are racy on directory creation so just run them one at a time.
         // Since there's not many this shouldn't be a problem.
-        run_cargo_test(cmd, &["--test-threads=1"], &[], "bootstrap", None, compiler, host, builder);
+        run_cargo_test(cargo, &["--test-threads=1"], &[], "bootstrap", None, host, builder);
     }
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@@ -3254,7 +3231,7 @@ impl Step for RustInstaller {
             bootstrap_host,
             bootstrap_host,
         );
-        run_cargo_test(cargo, &[], &[], "installer", None, compiler, bootstrap_host, builder);
+        run_cargo_test(cargo, &[], &[], "installer", None, bootstrap_host, builder);
 
         // We currently don't support running the test.sh script outside linux(?) environments.
         // Eventually this should likely migrate to #[test]s in rust-installer proper rather than a
@@ -3639,16 +3616,7 @@ impl Step for TestFloatParse {
             &[],
         );
 
-        run_cargo_test(
-            cargo_test,
-            &[],
-            &[],
-            crate_name,
-            crate_name,
-            compiler,
-            bootstrap_host,
-            builder,
-        );
+        run_cargo_test(cargo_test, &[], &[], crate_name, crate_name, bootstrap_host, builder);
 
         // Run the actual parse tests.
         let mut cargo_run = tool::prepare_tool_cargo(
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
index f9fb19ddb09..6b792108784 100644
--- a/src/bootstrap/src/core/builder/cargo.rs
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -121,6 +121,10 @@ impl Cargo {
         cargo
     }
 
+    pub fn compiler(&self) -> Compiler {
+        self.compiler
+    }
+
     pub fn into_cmd(self) -> BootstrapCommand {
         self.into()
     }
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 1c49063ef5c..910550b0a7d 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -2875,21 +2875,26 @@ impl Config {
             allowed_paths.push(":!library");
         }
 
-        // Look for a version to compare to based on the current commit.
-        // Only commits merged by bors will have CI artifacts.
-        let commit = match self.last_modified_commit(&allowed_paths, "download-rustc", if_unchanged)
-        {
-            Some(commit) => commit,
-            None => {
-                if if_unchanged {
-                    return None;
+        let commit = if self.rust_info.is_managed_git_subrepository() {
+            // Look for a version to compare to based on the current commit.
+            // Only commits merged by bors will have CI artifacts.
+            match self.last_modified_commit(&allowed_paths, "download-rustc", if_unchanged) {
+                Some(commit) => commit,
+                None => {
+                    if if_unchanged {
+                        return None;
+                    }
+                    println!("ERROR: could not find commit hash for downloading rustc");
+                    println!("HELP: maybe your repository history is too shallow?");
+                    println!("HELP: consider setting `rust.download-rustc=false` in config.toml");
+                    println!("HELP: or fetch enough history to include one upstream commit");
+                    crate::exit!(1);
                 }
-                println!("ERROR: could not find commit hash for downloading rustc");
-                println!("HELP: maybe your repository history is too shallow?");
-                println!("HELP: consider setting `rust.download-rustc=false` in config.toml");
-                println!("HELP: or fetch enough history to include one upstream commit");
-                crate::exit!(1);
             }
+        } else {
+            channel::read_commit_info_file(&self.src)
+                .map(|info| info.sha.trim().to_owned())
+                .expect("git-commit-info is missing in the project root")
         };
 
         if CiEnv::is_ci() && {
@@ -2926,10 +2931,8 @@ impl Config {
         let if_unchanged = || {
             if self.rust_info.is_from_tarball() {
                 // Git is needed for running "if-unchanged" logic.
-                println!(
-                    "WARNING: 'if-unchanged' has no effect on tarball sources; ignoring `download-ci-llvm`."
-                );
-                return false;
+                println!("ERROR: 'if-unchanged' is only compatible with Git managed sources.");
+                crate::exit!(1);
             }
 
             // Fetching the LLVM submodule is unnecessary for self-tests.
@@ -2971,6 +2974,11 @@ impl Config {
         option_name: &str,
         if_unchanged: bool,
     ) -> Option<String> {
+        assert!(
+            self.rust_info.is_managed_git_subrepository(),
+            "Can't run `Config::last_modified_commit` on a non-git source."
+        );
+
         // Look for a version to compare to based on the current commit.
         // Only commits merged by bors will have CI artifacts.
         let commit = get_closest_merge_commit(Some(&self.src), &self.git_config(), &[]).unwrap();
diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs
index c5e578ff351..f0a185ee3a7 100644
--- a/src/bootstrap/src/core/config/tests.rs
+++ b/src/bootstrap/src/core/config/tests.rs
@@ -92,7 +92,7 @@ fn detect_src_and_out() {
             //     `{build-dir}/bootstrap/debug/deps/bootstrap-c7ee91d5661e2804`
             // `{build-dir}` can be anywhere, not just in the rust project directory.
             let dep = Path::new(args.first().unwrap());
-            let expected_out = dep.ancestors().nth(4).unwrap();
+            let expected_out = dep.ancestors().nth(5).unwrap();
 
             assert_eq!(&cfg.out, expected_out);
         }
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 85d17c8fa50..a3eb781f147 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -335,4 +335,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Warning,
         summary: "Some stamp names in the build artifacts may have changed slightly (e.g., from `llvm-finished-building` to `.llvm-stamp`).",
     },
+    ChangeInfo {
+        change_id: 135729,
+        severity: ChangeSeverity::Info,
+        summary: "Change the compiler profile to default to rust.debug-assertions = true",
+    },
 ];
diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md
index 2f52ff5a99a..2b1de43c2f6 100644
--- a/src/ci/docker/README.md
+++ b/src/ci/docker/README.md
@@ -305,8 +305,6 @@ For targets: `mips-unknown-linux-gnu`
 - Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
 - Path and misc options > Use a mirror = ENABLE
 - Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
-- Path and misc options > Patches origin = Bundled, then local
-- Path and misc options > Local patch directory = /tmp/patches
 - Target options > Target Architecture = mips
 - Target options > ABI = o32
 - Target options > Endianness = Big endian
@@ -327,8 +325,6 @@ For targets: `mipsel-unknown-linux-gnu`
 - Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
 - Path and misc options > Use a mirror = ENABLE
 - Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
-- Path and misc options > Patches origin = Bundled, then local
-- Path and misc options > Local patch directory = /tmp/patches
 - Target options > Target Architecture = mips
 - Target options > ABI = o32
 - Target options > Endianness = Little endian
@@ -349,8 +345,6 @@ For targets: `mips64-unknown-linux-gnuabi64`
 - Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
 - Path and misc options > Use a mirror = ENABLE
 - Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
-- Path and misc options > Patches origin = Bundled, then local
-- Path and misc options > Local patch directory = /tmp/patches
 - Target options > Target Architecture = mips
 - Target options > ABI = n64
 - Target options > Endianness = Big endian
@@ -370,8 +364,6 @@ For targets: `mips64el-unknown-linux-gnuabi64`
 - Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
 - Path and misc options > Use a mirror = ENABLE
 - Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
-- Path and misc options > Patches origin = Bundled, then local
-- Path and misc options > Local patch directory = /tmp/patches
 - Target options > Target Architecture = mips
 - Target options > ABI = n64
 - Target options > Endianness = Little endian
diff --git a/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile
index c08febf423a..4a090dcdd50 100644
--- a/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile
@@ -11,7 +11,6 @@ RUN sh /scripts/rustbuild-setup.sh
 WORKDIR /tmp
 
 COPY scripts/crosstool-ng-build.sh /scripts/
-COPY host-x86_64/dist-mips-linux/patches/ /tmp/patches/
 COPY host-x86_64/dist-mips-linux/mips-linux-gnu.defconfig /tmp/crosstool.defconfig
 RUN /scripts/crosstool-ng-build.sh
 
diff --git a/src/ci/docker/host-x86_64/dist-mips-linux/mips-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-mips-linux/mips-linux-gnu.defconfig
index 75743fe8141..94db07922a2 100644
--- a/src/ci/docker/host-x86_64/dist-mips-linux/mips-linux-gnu.defconfig
+++ b/src/ci/docker/host-x86_64/dist-mips-linux/mips-linux-gnu.defconfig
@@ -2,8 +2,6 @@ CT_CONFIG_VERSION="4"
 CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
 CT_USE_MIRROR=y
 CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
-CT_PATCH_BUNDLED_LOCAL=y
-CT_LOCAL_PATCH_DIR="/tmp/patches"
 CT_ARCH_MIPS=y
 CT_ARCH_mips_o32=y
 CT_ARCH_ARCH="mips32r2"
diff --git a/src/ci/docker/host-x86_64/dist-mips-linux/patches/glibc/2.23/0001-MIPS-SPARC-fix-wrong-vfork-aliases-in-libpthread.so.patch b/src/ci/docker/host-x86_64/dist-mips-linux/patches/glibc/2.23/0001-MIPS-SPARC-fix-wrong-vfork-aliases-in-libpthread.so.patch
deleted file mode 100644
index 393084df324..00000000000
--- a/src/ci/docker/host-x86_64/dist-mips-linux/patches/glibc/2.23/0001-MIPS-SPARC-fix-wrong-vfork-aliases-in-libpthread.so.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-From 43c2948756bb6e144c7b871e827bba37d61ad3a3 Mon Sep 17 00:00:00 2001
-From: Aurelien Jarno <aurelien@aurel32.net>
-Date: Sat, 18 Jun 2016 19:11:23 +0200
-Subject: [PATCH 1/2] MIPS, SPARC: fix wrong vfork aliases in libpthread.so
-
-With recent binutils versions the GNU libc fails to build on at least
-MISP and SPARC, with this kind of error:
-
-  /home/aurel32/glibc/glibc-build/nptl/libpthread.so:(*IND*+0x0): multiple definition of `vfork@GLIBC_2.0'
-  /home/aurel32/glibc/glibc-build/nptl/libpthread.so::(.text+0xee50): first defined here
-
-It appears that on these architectures pt-vfork.S includes vfork.S
-(through the alpha version of pt-vfork.S) and that the __vfork aliases
-are not conditionalized on IS_IN (libc) like on other architectures.
-Therefore the aliases are also wrongly included in libpthread.so.
-
-Fix this by properly conditionalizing the aliases like on other
-architectures.
-
-Changelog:
-	* sysdeps/unix/sysv/linux/mips/vfork.S (__vfork): Conditionalize
-	hidden_def, weak_alias and strong_alias on [IS_IN (libc)].
-	* sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S: Likewise.
-	* sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S: Likewise.
----
- sysdeps/unix/sysv/linux/mips/vfork.S | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/sysdeps/unix/sysv/linux/mips/vfork.S b/sysdeps/unix/sysv/linux/mips/vfork.S
-index 8c6615143708..c0c0ce699159 100644
---- a/sysdeps/unix/sysv/linux/mips/vfork.S
-+++ b/sysdeps/unix/sysv/linux/mips/vfork.S
-@@ -106,6 +106,8 @@ L(error):
- #endif
- 	END(__vfork)
- 
-+#if IS_IN (libc)
- libc_hidden_def(__vfork)
- weak_alias (__vfork, vfork)
- strong_alias (__vfork, __libc_vfork)
-+#endif
--- 
-2.37.3
-
diff --git a/src/ci/docker/host-x86_64/dist-mips-linux/patches/glibc/2.23/0002-MIPS-SPARC-more-fixes-to-the-vfork-aliases-in-libpth.patch b/src/ci/docker/host-x86_64/dist-mips-linux/patches/glibc/2.23/0002-MIPS-SPARC-more-fixes-to-the-vfork-aliases-in-libpth.patch
deleted file mode 100644
index e28c7ae99f0..00000000000
--- a/src/ci/docker/host-x86_64/dist-mips-linux/patches/glibc/2.23/0002-MIPS-SPARC-more-fixes-to-the-vfork-aliases-in-libpth.patch
+++ /dev/null
@@ -1,63 +0,0 @@
-From b87c1ec3fa398646f042a68f0ce0f7d09c1348c7 Mon Sep 17 00:00:00 2001
-From: Aurelien Jarno <aurelien@aurel32.net>
-Date: Tue, 21 Jun 2016 23:59:37 +0200
-Subject: [PATCH 2/2] MIPS, SPARC: more fixes to the vfork aliases in
- libpthread.so
-
-Commit 43c29487 tried to fix the vfork aliases in libpthread.so on MIPS
-and SPARC, but failed to do it correctly, introducing an ABI change.
-
-This patch does the remaining changes needed to align the MIPS and SPARC
-vfork implementations with the other architectures. That way the the
-alpha version of pt-vfork.S works correctly for MIPS and SPARC. The
-changes for alpha were done in 82aab97c.
-
-Changelog:
-	* sysdeps/unix/sysv/linux/mips/vfork.S (__vfork): Rename into
-	__libc_vfork.
-	(__vfork) [IS_IN (libc)]: Remove alias.
-	(__libc_vfork) [IS_IN (libc)]: Define as an alias.
-	* sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S: Likewise.
-	* sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S: Likewise.
----
- sysdeps/unix/sysv/linux/mips/vfork.S | 12 ++++++------
- 1 file changed, 6 insertions(+), 6 deletions(-)
-
-diff --git a/sysdeps/unix/sysv/linux/mips/vfork.S b/sysdeps/unix/sysv/linux/mips/vfork.S
-index c0c0ce699159..1867c8626ebe 100644
---- a/sysdeps/unix/sysv/linux/mips/vfork.S
-+++ b/sysdeps/unix/sysv/linux/mips/vfork.S
-@@ -31,13 +31,13 @@
- LOCALSZ= 1
- FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK
- GPOFF= FRAMESZ-(1*SZREG)
--NESTED(__vfork,FRAMESZ,sp)
-+NESTED(__libc_vfork,FRAMESZ,sp)
- #ifdef __PIC__
- 	SETUP_GP
- #endif
- 	PTR_SUBU sp, FRAMESZ
- 	cfi_adjust_cfa_offset (FRAMESZ)
--	SETUP_GP64_REG (a5, __vfork)
-+	SETUP_GP64_REG (a5, __libc_vfork)
- #ifdef __PIC__
- 	SAVE_GP (GPOFF)
- #endif
-@@ -104,10 +104,10 @@ L(error):
- 	RESTORE_GP64_REG
- 	j		__syscall_error
- #endif
--	END(__vfork)
-+	END(__libc_vfork)
- 
- #if IS_IN (libc)
--libc_hidden_def(__vfork)
--weak_alias (__vfork, vfork)
--strong_alias (__vfork, __libc_vfork)
-+weak_alias (__libc_vfork, vfork)
-+strong_alias (__libc_vfork, __vfork)
-+libc_hidden_def (__vfork)
- #endif
--- 
-2.37.3
-
diff --git a/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile
index 10f31075e2d..18b0375f400 100644
--- a/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile
@@ -11,7 +11,6 @@ RUN sh /scripts/rustbuild-setup.sh
 WORKDIR /tmp
 
 COPY scripts/crosstool-ng-build.sh /scripts/
-COPY host-x86_64/dist-mips-linux/patches/ /tmp/patches/
 COPY host-x86_64/dist-mips64-linux/mips64-linux-gnu.defconfig /tmp/crosstool.defconfig
 RUN /scripts/crosstool-ng-build.sh
 
diff --git a/src/ci/docker/host-x86_64/dist-mips64-linux/mips64-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-mips64-linux/mips64-linux-gnu.defconfig
index 4b8f7a54920..f295a2fafc6 100644
--- a/src/ci/docker/host-x86_64/dist-mips64-linux/mips64-linux-gnu.defconfig
+++ b/src/ci/docker/host-x86_64/dist-mips64-linux/mips64-linux-gnu.defconfig
@@ -2,8 +2,6 @@ CT_CONFIG_VERSION="4"
 CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
 CT_USE_MIRROR=y
 CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
-CT_PATCH_BUNDLED_LOCAL=y
-CT_LOCAL_PATCH_DIR="/tmp/patches"
 CT_ARCH_MIPS=y
 CT_ARCH_mips_n64=y
 CT_ARCH_64=y
diff --git a/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile
index 5ab4a53de8a..87407203880 100644
--- a/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile
@@ -11,7 +11,6 @@ RUN sh /scripts/rustbuild-setup.sh
 WORKDIR /tmp
 
 COPY scripts/crosstool-ng-build.sh /scripts/
-COPY host-x86_64/dist-mips-linux/patches/ /tmp/patches/
 COPY host-x86_64/dist-mips64el-linux/mips64el-linux-gnu.defconfig /tmp/crosstool.defconfig
 RUN /scripts/crosstool-ng-build.sh
 
diff --git a/src/ci/docker/host-x86_64/dist-mips64el-linux/mips64el-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-mips64el-linux/mips64el-linux-gnu.defconfig
index 9c8eb5007b7..47d62463565 100644
--- a/src/ci/docker/host-x86_64/dist-mips64el-linux/mips64el-linux-gnu.defconfig
+++ b/src/ci/docker/host-x86_64/dist-mips64el-linux/mips64el-linux-gnu.defconfig
@@ -2,8 +2,6 @@ CT_CONFIG_VERSION="4"
 CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
 CT_USE_MIRROR=y
 CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
-CT_PATCH_BUNDLED_LOCAL=y
-CT_LOCAL_PATCH_DIR="/tmp/patches"
 CT_ARCH_MIPS=y
 CT_ARCH_mips_n64=y
 CT_ARCH_LE=y
diff --git a/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile
index 0bbaf00339d..553f6ea86b7 100644
--- a/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile
@@ -11,7 +11,6 @@ RUN sh /scripts/rustbuild-setup.sh
 WORKDIR /tmp
 
 COPY scripts/crosstool-ng-build.sh /scripts/
-COPY host-x86_64/dist-mips-linux/patches/ /tmp/patches/
 COPY host-x86_64/dist-mipsel-linux/mipsel-linux-gnu.defconfig /tmp/crosstool.defconfig
 RUN /scripts/crosstool-ng-build.sh
 
diff --git a/src/ci/docker/host-x86_64/dist-mipsel-linux/mipsel-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-mipsel-linux/mipsel-linux-gnu.defconfig
index a9dae121e53..5daa83ebc02 100644
--- a/src/ci/docker/host-x86_64/dist-mipsel-linux/mipsel-linux-gnu.defconfig
+++ b/src/ci/docker/host-x86_64/dist-mipsel-linux/mipsel-linux-gnu.defconfig
@@ -2,8 +2,6 @@ CT_CONFIG_VERSION="4"
 CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
 CT_USE_MIRROR=y
 CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
-CT_PATCH_BUNDLED_LOCAL=y
-CT_LOCAL_PATCH_DIR="/tmp/patches"
 CT_ARCH_MIPS=y
 CT_ARCH_mips_o32=y
 CT_ARCH_LE=y
diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
index 03ec77f507e..6c9071b4191 100644
--- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
@@ -56,9 +56,9 @@ ENV \
     CFLAGS_x86_64_fortanix_unknown_sgx="-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \
     CXX_x86_64_fortanix_unknown_sgx=clang++-11 \
     CXXFLAGS_x86_64_fortanix_unknown_sgx="-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \
-    AR_i686_unknown_freebsd=i686-unknown-freebsd12-ar \
-    CC_i686_unknown_freebsd=i686-unknown-freebsd12-clang \
-    CXX_i686_unknown_freebsd=i686-unknown-freebsd12-clang++ \
+    AR_i686_unknown_freebsd=i686-unknown-freebsd13-ar \
+    CC_i686_unknown_freebsd=i686-unknown-freebsd13-clang \
+    CXX_i686_unknown_freebsd=i686-unknown-freebsd13-clang++ \
     CC_aarch64_unknown_uefi=clang-11 \
     CXX_aarch64_unknown_uefi=clang++-11 \
     CC_i686_unknown_uefi=clang-11 \
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile
index f42e6f770eb..fd0f5da8c49 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile
@@ -29,9 +29,9 @@ COPY scripts/cmake.sh /scripts/
 RUN /scripts/cmake.sh
 
 ENV \
-    AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-ar \
-    CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-clang \
-    CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-clang++
+    AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-ar \
+    CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-clang \
+    CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-clang++
 
 ENV HOSTS=x86_64-unknown-freebsd
 
diff --git a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
index f52e306974c..9ca8cc740a5 100644
--- a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
@@ -1,4 +1,6 @@
-FROM ubuntu:22.04
+# We use the ghcr base image because ghcr doesn't have a rate limit
+# and the mingw-check-tidy job doesn't cache docker images in CI.
+FROM ghcr.io/rust-lang/ubuntu:22.04
 
 ARG DEBIAN_FRONTEND=noninteractive
 RUN apt-get update && apt-get install -y --no-install-recommends \
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index d1bc0519bc1..d2697ac27ab 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -123,6 +123,7 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
       build_args+=("--build-arg" "SCRIPT_ARG=${DOCKER_SCRIPT}")
     fi
 
+    GHCR_BUILDKIT_IMAGE="ghcr.io/rust-lang/buildkit:buildx-stable-1"
     # On non-CI jobs, we try to download a pre-built image from the rust-lang-ci
     # ghcr.io registry. If it is not possible, we fall back to building the image
     # locally.
@@ -140,7 +141,9 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
     elif [[ "$PR_CI_JOB" == "1" ]];
     then
         # Enable a new Docker driver so that --cache-from works with a registry backend
-        docker buildx create --use --driver docker-container
+        # Use a custom image to avoid DockerHub rate limits
+        docker buildx create --use --driver docker-container \
+          --driver-opt image=${GHCR_BUILDKIT_IMAGE}
 
         # Build the image using registry caching backend
         retry docker \
@@ -156,7 +159,9 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
             --password-stdin
 
         # Enable a new Docker driver so that --cache-from/to works with a registry backend
-        docker buildx create --use --driver docker-container
+        # Use a custom image to avoid DockerHub rate limits
+        docker buildx create --use --driver docker-container \
+          --driver-opt image=${GHCR_BUILDKIT_IMAGE}
 
         # Build the image using registry caching backend
         retry docker \
diff --git a/src/ci/docker/scripts/freebsd-toolchain.sh b/src/ci/docker/scripts/freebsd-toolchain.sh
index 0d02636db91..b927658b4fd 100755
--- a/src/ci/docker/scripts/freebsd-toolchain.sh
+++ b/src/ci/docker/scripts/freebsd-toolchain.sh
@@ -5,8 +5,8 @@ set -eux
 
 arch=$1
 binutils_version=2.40
-freebsd_version=12.3
-triple=$arch-unknown-freebsd12
+freebsd_version=13.4
+triple=$arch-unknown-freebsd13
 sysroot=/usr/local/$triple
 
 hide_output() {
@@ -59,7 +59,7 @@ done
 
 # Originally downloaded from:
 # URL=https://download.freebsd.org/ftp/releases/${freebsd_arch}/${freebsd_version}-RELEASE/base.txz
-URL=https://ci-mirrors.rust-lang.org/rustc/2022-05-06-freebsd-${freebsd_version}-${freebsd_arch}-base.txz
+URL=https://ci-mirrors.rust-lang.org/rustc/2024-09-13-freebsd-${freebsd_version}-${freebsd_arch}-base.txz
 curl "$URL" | tar xJf - -C "$sysroot" --wildcards "${files_to_extract[@]}"
 
 # Clang can do cross-builds out of the box, if we give it the right
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 1ab70e4e0aa..5e95e3721df 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -35,6 +35,10 @@ runners:
     os: windows-2022
     <<: *base-job
 
+  - &job-windows-25
+    os: windows-2025
+    <<: *base-job
+
   - &job-windows-8c
     os: windows-2022-8core-32gb
     <<: *base-job
@@ -44,6 +48,8 @@ runners:
     <<: *base-job
 
   - &job-aarch64-linux
+    # Free some disk space to avoid running out of space during the build.
+    free_disk: true
     os: ubuntu-22.04-arm
 
 envs:
@@ -442,17 +448,30 @@ auto:
   #  Windows Builders  #
   ######################
 
-  - name: x86_64-msvc
+  - name: x86_64-msvc-1
     env:
       RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler
-      SCRIPT: make ci-msvc
-    <<: *job-windows-8c
+      SCRIPT: make ci-msvc-py
+    <<: *job-windows-25
+
+  - name: x86_64-msvc-2
+    env:
+      RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler
+      SCRIPT: make ci-msvc-ps1
+    <<: *job-windows-25
 
-  - name: i686-msvc
+  # i686-msvc is split into two jobs to run tests in parallel.
+  - name: i686-msvc-1
     env:
       RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
-      SCRIPT: make ci-msvc
-    <<: *job-windows-8c
+      SCRIPT: make ci-msvc-py
+    <<: *job-windows
+
+  - name: i686-msvc-2
+    env:
+      RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
+      SCRIPT: make ci-msvc-ps1
+    <<: *job-windows
 
   # x86_64-msvc-ext is split into multiple jobs to run tests in parallel.
   - name: x86_64-msvc-ext1
diff --git a/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs b/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs
index 576bbcea965..8983915d78a 100644
--- a/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs
+++ b/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs
@@ -18,8 +18,8 @@ use std::path::Path;
 
 use rustc_ast_pretty::pprust::item_to_string;
 use rustc_data_structures::sync::Lrc;
-use rustc_driver::{Compilation, RunCompiler};
-use rustc_interface::interface::Compiler;
+use rustc_driver::{Compilation, run_compiler};
+use rustc_interface::interface::{Compiler, Config};
 use rustc_middle::ty::TyCtxt;
 
 struct MyFileLoader;
@@ -51,6 +51,10 @@ fn main() {
 struct MyCallbacks;
 
 impl rustc_driver::Callbacks for MyCallbacks {
+    fn config(&mut self, config: &mut Config) {
+        config.file_loader = Some(Box::new(MyFileLoader));
+    }
+
     fn after_crate_root_parsing(
         &mut self,
         _compiler: &Compiler,
@@ -83,10 +87,5 @@ impl rustc_driver::Callbacks for MyCallbacks {
 }
 
 fn main() {
-    match RunCompiler::new(&["main.rs".to_string()], &mut MyCallbacks) {
-        mut compiler => {
-            compiler.set_file_loader(Some(Box::new(MyFileLoader)));
-            compiler.run();
-        }
-    }
+    run_compiler(&["main.rs".to_string()], &mut MyCallbacks);
 }
diff --git a/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs b/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs
index 90a85d5db21..c894b60444a 100644
--- a/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs
+++ b/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs
@@ -18,8 +18,8 @@ use std::path::Path;
 
 use rustc_ast_pretty::pprust::item_to_string;
 use rustc_data_structures::sync::Lrc;
-use rustc_driver::{Compilation, RunCompiler};
-use rustc_interface::interface::Compiler;
+use rustc_driver::{Compilation, run_compiler};
+use rustc_interface::interface::{Compiler, Config};
 use rustc_middle::ty::TyCtxt;
 
 struct MyFileLoader;
@@ -51,6 +51,10 @@ fn main() {
 struct MyCallbacks;
 
 impl rustc_driver::Callbacks for MyCallbacks {
+    fn config(&mut self, config: &mut Config) {
+        config.file_loader = Some(Box::new(MyFileLoader));
+    }
+
     fn after_crate_root_parsing(
         &mut self,
         _compiler: &Compiler,
@@ -90,10 +94,5 @@ impl rustc_driver::Callbacks for MyCallbacks {
 }
 
 fn main() {
-    match RunCompiler::new(&["main.rs".to_string()], &mut MyCallbacks) {
-        mut compiler => {
-            compiler.set_file_loader(Some(Box::new(MyFileLoader)));
-            compiler.run();
-        }
-    }
+    run_compiler(&["main.rs".to_string()], &mut MyCallbacks);
 }
diff --git a/src/doc/rustc-dev-guide/src/rustc-driver/intro.md b/src/doc/rustc-dev-guide/src/rustc-driver/intro.md
index a6234dc129f..40500e6bc7a 100644
--- a/src/doc/rustc-dev-guide/src/rustc-driver/intro.md
+++ b/src/doc/rustc-dev-guide/src/rustc-driver/intro.md
@@ -6,7 +6,7 @@ The [`rustc_driver`] is essentially `rustc`'s `main` function.
 It acts as the glue for running the various phases of the compiler in the correct order,
 using the interface defined in the [`rustc_interface`] crate. Where possible, using [`rustc_driver`] rather than [`rustc_interface`] is recommended.
 
-The main entry point of [`rustc_driver`] is [`rustc_driver::RunCompiler`][rd_rc].
+The main entry point of [`rustc_driver`] is [`rustc_driver::run_compiler`][rd_rc].
 This builder accepts the same command-line args as rustc as well as an implementation of [`Callbacks`][cb] and a couple of other optional options.
 [`Callbacks`][cb] is a `trait` that allows for custom compiler configuration,
 as well as allowing custom code to run after different phases of the compilation.
@@ -40,7 +40,7 @@ specifically [`rustc_driver_impl::run_compiler`][rdi_rc]
 [cb]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/trait.Callbacks.html
 [example]: https://github.com/rust-lang/rustc-dev-guide/blob/master/examples/rustc-interface-example.rs
 [i_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/interface/fn.run_compiler.html
-[rd_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/struct.RunCompiler.html
+[rd_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/fn.run_compiler.html
 [rdi_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver_impl/fn.run_compiler.html
 [stupid-stats]: https://github.com/nrc/stupid-stats
 [`nightly-rustc`]: https://doc.rust-lang.org/nightly/nightly-rustc/
diff --git a/src/doc/rustc-dev-guide/src/stability.md b/src/doc/rustc-dev-guide/src/stability.md
index 1bfe911c900..230925252ba 100644
--- a/src/doc/rustc-dev-guide/src/stability.md
+++ b/src/doc/rustc-dev-guide/src/stability.md
@@ -34,7 +34,8 @@ Previously, due to a [rustc bug], stable items inside unstable modules were
 available to stable code in that location.
 As of <!-- date-check --> September 2024, items with [accidentally stabilized
 paths] are marked with the `#[rustc_allowed_through_unstable_modules]` attribute
-to prevent code dependent on those paths from breaking.
+to prevent code dependent on those paths from breaking. Do *not* add this attribute
+to any more items unless that is needed to avoid breaking changes.
 
 The `unstable` attribute may also have the `soft` value, which makes it a
 future-incompatible deny-by-default lint instead of a hard error. This is used
diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md
index 69f4c864186..426a6ff1da5 100644
--- a/src/doc/rustc-dev-guide/src/tests/directives.md
+++ b/src/doc/rustc-dev-guide/src/tests/directives.md
@@ -94,7 +94,8 @@ for more details.
 | Directive                         | Explanation                                                                                                              | Supported test suites                        | Possible values                                                                         |
 |-----------------------------------|--------------------------------------------------------------------------------------------------------------------------|----------------------------------------------|-----------------------------------------------------------------------------------------|
 | `check-run-results`               | Check run test binary `run-{pass,fail}` output snapshot                                                                  | `ui`, `crashes`, `incremental` if `run-pass` | N/A                                                                                     |
-| `error-pattern`                   | Check that output contains a regex pattern                                                                               | `ui`, `crashes`, `incremental` if `run-pass` | Regex                                                                                   |
+| `error-pattern`                   | Check that output contains a specific string                                                                             | `ui`, `crashes`, `incremental` if `run-pass` | String                                                                                   |
+| `regex-error-pattern`             | Check that output contains a regex pattern                                                                               | `ui`, `crashes`, `incremental` if `run-pass` | Regex                                                                                   |
 | `check-stdout`                    | Check `stdout` against `error-pattern`s from running test binary[^check_stdout]                                          | `ui`, `crashes`, `incremental`               | N/A                                                                                     |
 | `normalize-stderr-32bit`          | Normalize actual stderr (for 32-bit platforms) with a rule `"<raw>" -> "<normalized>"` before comparing against snapshot | `ui`, `incremental`                          | `"<RAW>" -> "<NORMALIZED>"`, `<RAW>`/`<NORMALIZED>` is regex capture and replace syntax |
 | `normalize-stderr-64bit`          | Normalize actual stderr (for 64-bit platforms) with a rule `"<raw>" -> "<normalized>"` before comparing against snapshot | `ui`, `incremental`                          | `"<RAW>" -> "<NORMALIZED>"`, `<RAW>`/`<NORMALIZED>` is regex capture and replace syntax |
@@ -151,6 +152,8 @@ Some examples of `X` in `ignore-X` or `only-X`:
   `compare-mode-split-dwarf`, `compare-mode-split-dwarf-single`
 - The two different test modes used by coverage tests:
   `ignore-coverage-map`, `ignore-coverage-run`
+- When testing a dist toolchain: `dist`
+  - This needs to be enabled with `COMPILETEST_ENABLE_DIST_TESTS=1`
 
 The following directives will check rustc build settings and target
 settings:
diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md
index 1c240d1255a..96e3b58f471 100644
--- a/src/doc/rustc/src/platform-support/nto-qnx.md
+++ b/src/doc/rustc/src/platform-support/nto-qnx.md
@@ -78,7 +78,7 @@ extern "C" {
 }
 
 #[no_mangle]
-pub extern "C" fn main(_argc: isize, _argv: *const *const u8) -> isize {
+pub extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int {
     const HELLO: &'static str = "Hello World, the answer is %d\n\0";
     unsafe {
         printf(HELLO.as_ptr() as *const _, 42);
diff --git a/src/doc/unstable-book/src/language-features/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md
index 32b882e763d..1122bbc5a87 100644
--- a/src/doc/unstable-book/src/language-features/lang-items.md
+++ b/src/doc/unstable-book/src/language-features/lang-items.md
@@ -46,14 +46,15 @@ allocation. A freestanding program that uses the `Box` sugar for dynamic
 allocations via `malloc` and `free`:
 
 ```rust,ignore (libc-is-finicky)
-#![feature(lang_items, start, core_intrinsics, rustc_private, panic_unwind, rustc_attrs)]
+#![feature(lang_items, core_intrinsics, rustc_private, panic_unwind, rustc_attrs)]
 #![allow(internal_features)]
 #![no_std]
+#![no_main]
 
 extern crate libc;
 extern crate unwind;
 
-use core::ffi::c_void;
+use core::ffi::{c_int, c_void};
 use core::intrinsics;
 use core::panic::PanicInfo;
 use core::ptr::NonNull;
@@ -91,8 +92,8 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
     p
 }
 
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(_argc: c_int, _argv: *const *const u8) -> c_int {
     let _x = Box::new(1);
 
     0
diff --git a/src/doc/unstable-book/src/language-features/start.md b/src/doc/unstable-book/src/language-features/start.md
deleted file mode 100644
index 09e4875a2e4..00000000000
--- a/src/doc/unstable-book/src/language-features/start.md
+++ /dev/null
@@ -1,59 +0,0 @@
-# `start`
-
-The tracking issue for this feature is: [#29633]
-
-[#29633]: https://github.com/rust-lang/rust/issues/29633
-
-------------------------
-
-Allows you to mark a function as the entry point of the executable, which is
-necessary in `#![no_std]` environments.
-
-The function marked `#[start]` is passed the command line parameters in the same
-format as the C main function (aside from the integer types being used).
-It has to be non-generic and have the following signature:
-
-```rust,ignore (only-for-syntax-highlight)
-# let _:
-fn(isize, *const *const u8) -> isize
-# ;
-```
-
-This feature should not be confused with the `start` *lang item* which is
-defined by the `std` crate and is written `#[lang = "start"]`.
-
-## Usage together with the `std` crate
-
-`#[start]` can be used in combination with the `std` crate, in which case the
-normal `main` function (which would get called from the `std` crate) won't be
-used as an entry point.
-The initialization code in `std` will be skipped this way.
-
-Example:
-
-```rust
-#![feature(start)]
-
-#[start]
-fn start(_argc: isize, _argv: *const *const u8) -> isize {
-    0
-}
-```
-
-Unwinding the stack past the `#[start]` function is currently considered
-Undefined Behavior (for any unwinding implementation):
-
-```rust,ignore (UB)
-#![feature(start)]
-
-#[start]
-fn start(_argc: isize, _argv: *const *const u8) -> isize {
-    std::panic::catch_unwind(|| {
-        panic!(); // panic safely gets caught or safely aborts execution
-    });
-
-    panic!(); // UB!
-
-    0
-}
-```
diff --git a/src/etc/dec2flt_table.py b/src/etc/dec2flt_table.py
index 791186de9c1..ecfdacc1f31 100755
--- a/src/etc/dec2flt_table.py
+++ b/src/etc/dec2flt_table.py
@@ -43,10 +43,10 @@ def main():
 
     print(HEADER.strip())
     print()
-    print("pub const SMALLEST_POWER_OF_FIVE: i32 = {};".format(min_exp))
-    print("pub const LARGEST_POWER_OF_FIVE: i32 = {};".format(max_exp))
-    print("pub const N_POWERS_OF_FIVE: usize = ", end="")
-    print("(LARGEST_POWER_OF_FIVE - SMALLEST_POWER_OF_FIVE + 1) as usize;")
+    print("pub(super) const SMALLEST_POWER_OF_FIVE: i32 = {};".format(min_exp))
+    print("pub(super) const LARGEST_POWER_OF_FIVE: i32 = {};".format(max_exp))
+    print("pub(super) const N_POWERS_OF_FIVE: usize =")
+    print("    (LARGEST_POWER_OF_FIVE - SMALLEST_POWER_OF_FIVE + 1) as usize;")
     print()
     print_proper_powers(min_exp, max_exp, bias)
 
@@ -97,7 +97,7 @@ def print_proper_powers(min_exp, max_exp, bias):
     print(STATIC_WARNING.strip())
     print("#[rustfmt::skip]")
     typ = "[(u64, u64); N_POWERS_OF_FIVE]"
-    print("pub static POWER_OF_FIVE_128: {} = [".format(typ))
+    print("pub(super) static POWER_OF_FIVE_128: {} = [".format(typ))
     for c, exp in powers:
         hi = "0x{:x}".format(c // (1 << 64))
         lo = "0x{:x}".format(c % (1 << 64))
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index bfa789b1f39..bdd44b4a993 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -389,6 +389,49 @@ fn write_with_opt_paren<T: fmt::Display>(
     Ok(())
 }
 
+impl Display<'_> {
+    fn display_sub_cfgs(
+        &self,
+        fmt: &mut fmt::Formatter<'_>,
+        sub_cfgs: &[Cfg],
+        separator: &str,
+    ) -> fmt::Result {
+        let short_longhand = self.1.is_long() && {
+            let all_crate_features =
+                sub_cfgs.iter().all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::feature, Some(_))));
+            let all_target_features = sub_cfgs
+                .iter()
+                .all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::target_feature, Some(_))));
+
+            if all_crate_features {
+                fmt.write_str("crate features ")?;
+                true
+            } else if all_target_features {
+                fmt.write_str("target features ")?;
+                true
+            } else {
+                false
+            }
+        };
+
+        for (i, sub_cfg) in sub_cfgs.iter().enumerate() {
+            if i != 0 {
+                fmt.write_str(separator)?;
+            }
+            if let (true, Cfg::Cfg(_, Some(feat))) = (short_longhand, sub_cfg) {
+                if self.1.is_html() {
+                    write!(fmt, "<code>{feat}</code>")?;
+                } else {
+                    write!(fmt, "`{feat}`")?;
+                }
+            } else {
+                write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))?;
+            }
+        }
+        Ok(())
+    }
+}
+
 impl fmt::Display for Display<'_> {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self.0 {
@@ -408,79 +451,9 @@ impl fmt::Display for Display<'_> {
 
             Cfg::Any(ref sub_cfgs) => {
                 let separator = if sub_cfgs.iter().all(Cfg::is_simple) { " or " } else { ", or " };
-
-                let short_longhand = self.1.is_long() && {
-                    let all_crate_features = sub_cfgs
-                        .iter()
-                        .all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::feature, Some(_))));
-                    let all_target_features = sub_cfgs
-                        .iter()
-                        .all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::target_feature, Some(_))));
-
-                    if all_crate_features {
-                        fmt.write_str("crate features ")?;
-                        true
-                    } else if all_target_features {
-                        fmt.write_str("target features ")?;
-                        true
-                    } else {
-                        false
-                    }
-                };
-
-                for (i, sub_cfg) in sub_cfgs.iter().enumerate() {
-                    if i != 0 {
-                        fmt.write_str(separator)?;
-                    }
-                    if let (true, Cfg::Cfg(_, Some(feat))) = (short_longhand, sub_cfg) {
-                        if self.1.is_html() {
-                            write!(fmt, "<code>{feat}</code>")?;
-                        } else {
-                            write!(fmt, "`{feat}`")?;
-                        }
-                    } else {
-                        write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))?;
-                    }
-                }
-                Ok(())
-            }
-
-            Cfg::All(ref sub_cfgs) => {
-                let short_longhand = self.1.is_long() && {
-                    let all_crate_features = sub_cfgs
-                        .iter()
-                        .all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::feature, Some(_))));
-                    let all_target_features = sub_cfgs
-                        .iter()
-                        .all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::target_feature, Some(_))));
-
-                    if all_crate_features {
-                        fmt.write_str("crate features ")?;
-                        true
-                    } else if all_target_features {
-                        fmt.write_str("target features ")?;
-                        true
-                    } else {
-                        false
-                    }
-                };
-
-                for (i, sub_cfg) in sub_cfgs.iter().enumerate() {
-                    if i != 0 {
-                        fmt.write_str(" and ")?;
-                    }
-                    if let (true, Cfg::Cfg(_, Some(feat))) = (short_longhand, sub_cfg) {
-                        if self.1.is_html() {
-                            write!(fmt, "<code>{feat}</code>")?;
-                        } else {
-                            write!(fmt, "`{feat}`")?;
-                        }
-                    } else {
-                        write_with_opt_paren(fmt, !sub_cfg.is_simple(), Display(sub_cfg, self.1))?;
-                    }
-                }
-                Ok(())
+                self.display_sub_cfgs(fmt, sub_cfgs, separator)
             }
+            Cfg::All(ref sub_cfgs) => self.display_sub_cfgs(fmt, sub_cfgs, " and "),
 
             Cfg::True => fmt.write_str("everywhere"),
             Cfg::False => fmt.write_str("nowhere"),
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 0dda3466a71..ad67c2ba245 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -1,10 +1,10 @@
-use std::sync::atomic::AtomicBool;
-use std::sync::{Arc, LazyLock};
+use std::sync::LazyLock;
 use std::{io, mem};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::unord::UnordSet;
+use rustc_driver::USING_INTERNAL_FEATURES;
 use rustc_errors::TerminalUrl;
 use rustc_errors::codes::*;
 use rustc_errors::emitter::{
@@ -221,7 +221,6 @@ pub(crate) fn create_config(
         ..
     }: RustdocOptions,
     RenderOptions { document_private, .. }: &RenderOptions,
-    using_internal_features: Arc<AtomicBool>,
 ) -> rustc_interface::Config {
     // Add the doc cfg into the doc build.
     cfgs.push("doc".to_string());
@@ -316,7 +315,7 @@ pub(crate) fn create_config(
         make_codegen_backend: None,
         registry: rustc_driver::diagnostics_registry(),
         ice_file: None,
-        using_internal_features,
+        using_internal_features: &USING_INTERNAL_FEATURES,
         expanded_args,
     }
 }
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 009e9662933..8c3e28ecec3 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -193,7 +193,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions
         make_codegen_backend: None,
         registry: rustc_driver::diagnostics_registry(),
         ice_file: None,
-        using_internal_features: Arc::default(),
+        using_internal_features: &rustc_driver::USING_INTERNAL_FEATURES,
         expanded_args: options.expanded_args.clone(),
     };
 
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 92935c72b47..20a8dc72491 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -150,8 +150,9 @@ pub(crate) fn comma_sep<T: Display>(
     items: impl Iterator<Item = T>,
     space_after_comma: bool,
 ) -> impl Display {
-    display_fn(move |f| {
-        for (i, item) in items.enumerate() {
+    let items = Cell::new(Some(items));
+    fmt::from_fn(move |f| {
+        for (i, item) in items.take().unwrap().enumerate() {
             if i != 0 {
                 write!(f, ",{}", if space_after_comma { " " } else { "" })?;
             }
@@ -165,7 +166,7 @@ pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>(
     bounds: &'a [clean::GenericBound],
     cx: &'a Context<'tcx>,
 ) -> impl Display + 'a + Captures<'tcx> {
-    display_fn(move |f| {
+    fmt::from_fn(move |f| {
         let mut bounds_dup = FxHashSet::default();
 
         for (i, bound) in bounds.iter().filter(|b| bounds_dup.insert(*b)).enumerate() {
@@ -183,7 +184,7 @@ impl clean::GenericParamDef {
         &'a self,
         cx: &'a Context<'tcx>,
     ) -> impl Display + 'a + Captures<'tcx> {
-        display_fn(move |f| match &self.kind {
+        fmt::from_fn(move |f| match &self.kind {
             clean::GenericParamDefKind::Lifetime { outlives } => {
                 write!(f, "{}", self.name)?;
 
@@ -238,7 +239,7 @@ impl clean::Generics {
         &'a self,
         cx: &'a Context<'tcx>,
     ) -> impl Display + 'a + Captures<'tcx> {
-        display_fn(move |f| {
+        fmt::from_fn(move |f| {
             let mut real_params = self.params.iter().filter(|p| !p.is_synthetic_param()).peekable();
             if real_params.peek().is_none() {
                 return Ok(());
@@ -268,12 +269,12 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
     indent: usize,
     ending: Ending,
 ) -> impl Display + 'a + Captures<'tcx> {
-    display_fn(move |f| {
+    fmt::from_fn(move |f| {
         let mut where_predicates = gens
             .where_predicates
             .iter()
             .map(|pred| {
-                display_fn(move |f| {
+                fmt::from_fn(move |f| {
                     if f.alternate() {
                         f.write_str(" ")?;
                     } else {
@@ -376,17 +377,15 @@ impl clean::Lifetime {
 impl clean::ConstantKind {
     pub(crate) fn print(&self, tcx: TyCtxt<'_>) -> impl Display + '_ {
         let expr = self.expr(tcx);
-        display_fn(
-            move |f| {
-                if f.alternate() { f.write_str(&expr) } else { write!(f, "{}", Escape(&expr)) }
-            },
-        )
+        fmt::from_fn(move |f| {
+            if f.alternate() { f.write_str(&expr) } else { write!(f, "{}", Escape(&expr)) }
+        })
     }
 }
 
 impl clean::PolyTrait {
     fn print<'a, 'tcx: 'a>(&'a self, cx: &'a Context<'tcx>) -> impl Display + 'a + Captures<'tcx> {
-        display_fn(move |f| {
+        fmt::from_fn(move |f| {
             print_higher_ranked_params_with_space(&self.generic_params, cx, "for").fmt(f)?;
             self.trait_.print(cx).fmt(f)
         })
@@ -398,7 +397,7 @@ impl clean::GenericBound {
         &'a self,
         cx: &'a Context<'tcx>,
     ) -> impl Display + 'a + Captures<'tcx> {
-        display_fn(move |f| match self {
+        fmt::from_fn(move |f| match self {
             clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()),
             clean::GenericBound::TraitBound(ty, modifiers) => {
                 // `const` and `~const` trait bounds are experimental; don't render them.
@@ -430,7 +429,7 @@ impl clean::GenericBound {
 
 impl clean::GenericArgs {
     fn print<'a, 'tcx: 'a>(&'a self, cx: &'a Context<'tcx>) -> impl Display + 'a + Captures<'tcx> {
-        display_fn(move |f| {
+        fmt::from_fn(move |f| {
             match self {
                 clean::GenericArgs::AngleBracketed { args, constraints } => {
                     if !args.is_empty() || !constraints.is_empty() {
@@ -950,7 +949,7 @@ fn tybounds<'a, 'tcx: 'a>(
     lt: &'a Option<clean::Lifetime>,
     cx: &'a Context<'tcx>,
 ) -> impl Display + 'a + Captures<'tcx> {
-    display_fn(move |f| {
+    fmt::from_fn(move |f| {
         for (i, bound) in bounds.iter().enumerate() {
             if i > 0 {
                 write!(f, " + ")?;
@@ -971,7 +970,7 @@ fn print_higher_ranked_params_with_space<'a, 'tcx: 'a>(
     cx: &'a Context<'tcx>,
     keyword: &'static str,
 ) -> impl Display + 'a + Captures<'tcx> {
-    display_fn(move |f| {
+    fmt::from_fn(move |f| {
         if !params.is_empty() {
             f.write_str(keyword)?;
             f.write_str(if f.alternate() { "<" } else { "&lt;" })?;
@@ -982,13 +981,13 @@ fn print_higher_ranked_params_with_space<'a, 'tcx: 'a>(
     })
 }
 
-pub(crate) fn anchor<'a, 'cx: 'a>(
+pub(crate) fn anchor<'a: 'cx, 'cx>(
     did: DefId,
     text: Symbol,
-    cx: &'cx Context<'_>,
-) -> impl Display + 'a {
-    let parts = href(did, cx);
-    display_fn(move |f| {
+    cx: &'cx Context<'a>,
+) -> impl Display + Captures<'a> + 'cx {
+    fmt::from_fn(move |f| {
+        let parts = href(did, cx);
         if let Ok((url, short_ty, fqp)) = parts {
             write!(
                 f,
@@ -1150,7 +1149,7 @@ fn fmt_type(
             }
         }
         clean::BorrowedRef { lifetime: ref l, mutability, type_: ref ty } => {
-            let lt = display_fn(|f| match l {
+            let lt = fmt::from_fn(|f| match l {
                 Some(l) => write!(f, "{} ", l.print()),
                 _ => Ok(()),
             });
@@ -1270,7 +1269,7 @@ impl clean::Type {
         &'a self,
         cx: &'a Context<'tcx>,
     ) -> impl Display + 'b + Captures<'tcx> {
-        display_fn(move |f| fmt_type(self, f, false, cx))
+        fmt::from_fn(move |f| fmt_type(self, f, false, cx))
     }
 }
 
@@ -1279,7 +1278,7 @@ impl clean::Path {
         &'a self,
         cx: &'a Context<'tcx>,
     ) -> impl Display + 'b + Captures<'tcx> {
-        display_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx))
+        fmt::from_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx))
     }
 }
 
@@ -1289,7 +1288,7 @@ impl clean::Impl {
         use_absolute: bool,
         cx: &'a Context<'tcx>,
     ) -> impl Display + 'a + Captures<'tcx> {
-        display_fn(move |f| {
+        fmt::from_fn(move |f| {
             f.write_str("impl")?;
             self.generics.print(cx).fmt(f)?;
             f.write_str(" ")?;
@@ -1407,7 +1406,7 @@ impl clean::Arguments {
         &'a self,
         cx: &'a Context<'tcx>,
     ) -> impl Display + 'a + Captures<'tcx> {
-        display_fn(move |f| {
+        fmt::from_fn(move |f| {
             for (i, input) in self.values.iter().enumerate() {
                 write!(f, "{}: ", input.name)?;
                 input.type_.print(cx).fmt(f)?;
@@ -1447,7 +1446,7 @@ impl clean::FnDecl {
         &'a self,
         cx: &'a Context<'tcx>,
     ) -> impl Display + 'b + Captures<'tcx> {
-        display_fn(move |f| {
+        fmt::from_fn(move |f| {
             let ellipsis = if self.c_variadic { ", ..." } else { "" };
             if f.alternate() {
                 write!(
@@ -1481,10 +1480,10 @@ impl clean::FnDecl {
         indent: usize,
         cx: &'a Context<'tcx>,
     ) -> impl Display + 'a + Captures<'tcx> {
-        display_fn(move |f| {
+        fmt::from_fn(move |f| {
             // First, generate the text form of the declaration, with no line wrapping, and count the bytes.
             let mut counter = WriteCounter(0);
-            write!(&mut counter, "{:#}", display_fn(|f| { self.inner_full_print(None, f, cx) }))
+            write!(&mut counter, "{:#}", fmt::from_fn(|f| { self.inner_full_print(None, f, cx) }))
                 .unwrap();
             // If the text form was over 80 characters wide, we will line-wrap our output.
             let line_wrapping_indent =
@@ -1566,7 +1565,7 @@ impl clean::FnDecl {
         &'a self,
         cx: &'a Context<'tcx>,
     ) -> impl Display + 'a + Captures<'tcx> {
-        display_fn(move |f| match &self.output {
+        fmt::from_fn(move |f| match &self.output {
             clean::Tuple(tys) if tys.is_empty() => Ok(()),
             ty if f.alternate() => {
                 write!(f, " -> {:#}", ty.print(cx))
@@ -1618,7 +1617,7 @@ pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>(
     };
 
     let is_doc_hidden = item.is_doc_hidden();
-    display_fn(move |f| {
+    fmt::from_fn(move |f| {
         if is_doc_hidden {
             f.write_str("#[doc(hidden)] ")?;
         }
@@ -1692,7 +1691,7 @@ impl clean::Import {
         &'a self,
         cx: &'a Context<'tcx>,
     ) -> impl Display + 'a + Captures<'tcx> {
-        display_fn(move |f| match self.kind {
+        fmt::from_fn(move |f| match self.kind {
             clean::ImportKind::Simple(name) => {
                 if name == self.source.path.last() {
                     write!(f, "use {};", self.source.print(cx))
@@ -1716,7 +1715,7 @@ impl clean::ImportSource {
         &'a self,
         cx: &'a Context<'tcx>,
     ) -> impl Display + 'a + Captures<'tcx> {
-        display_fn(move |f| match self.did {
+        fmt::from_fn(move |f| match self.did {
             Some(did) => resolved_path(f, did, &self.path, true, false, cx),
             _ => {
                 for seg in &self.path.segments[..self.path.segments.len() - 1] {
@@ -1744,7 +1743,7 @@ impl clean::AssocItemConstraint {
         &'a self,
         cx: &'a Context<'tcx>,
     ) -> impl Display + 'a + Captures<'tcx> {
-        display_fn(move |f| {
+        fmt::from_fn(move |f| {
             f.write_str(self.assoc.name.as_str())?;
             self.assoc.args.print(cx).fmt(f)?;
             match self.kind {
@@ -1765,7 +1764,7 @@ impl clean::AssocItemConstraint {
 }
 
 pub(crate) fn print_abi_with_space(abi: ExternAbi) -> impl Display {
-    display_fn(move |f| {
+    fmt::from_fn(move |f| {
         let quot = if f.alternate() { "\"" } else { "&quot;" };
         match abi {
             ExternAbi::Rust => Ok(()),
@@ -1783,7 +1782,7 @@ impl clean::GenericArg {
         &'a self,
         cx: &'a Context<'tcx>,
     ) -> impl Display + 'a + Captures<'tcx> {
-        display_fn(move |f| match self {
+        fmt::from_fn(move |f| match self {
             clean::GenericArg::Lifetime(lt) => lt.print().fmt(f),
             clean::GenericArg::Type(ty) => ty.print(cx).fmt(f),
             clean::GenericArg::Const(ct) => ct.print(cx.tcx()).fmt(f),
@@ -1797,24 +1796,9 @@ impl clean::Term {
         &'a self,
         cx: &'a Context<'tcx>,
     ) -> impl Display + 'a + Captures<'tcx> {
-        display_fn(move |f| match self {
+        fmt::from_fn(move |f| match self {
             clean::Term::Type(ty) => ty.print(cx).fmt(f),
             clean::Term::Constant(ct) => ct.print(cx.tcx()).fmt(f),
         })
     }
 }
-
-pub(crate) fn display_fn(f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl Display {
-    struct WithFormatter<F>(Cell<Option<F>>);
-
-    impl<F> Display for WithFormatter<F>
-    where
-        F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
-    {
-        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            (self.0.take()).unwrap()(f)
-        }
-    }
-
-    WithFormatter(Cell::new(Some(f)))
-}
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 62cf2b63f7f..7b2aee4b4a5 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -233,7 +233,7 @@ pub(super) fn write_code(
     out: &mut impl Write,
     src: &str,
     href_context: Option<HrefContext<'_, '_>>,
-    decoration_info: Option<DecorationInfo>,
+    decoration_info: Option<&DecorationInfo>,
 ) {
     // This replace allows to fix how the code source with DOS backline characters is displayed.
     let src = src.replace("\r\n", "\n");
@@ -510,12 +510,12 @@ struct Decorations {
 }
 
 impl Decorations {
-    fn new(info: DecorationInfo) -> Self {
+    fn new(info: &DecorationInfo) -> Self {
         // Extract tuples (start, end, kind) into separate sequences of (start, kind) and (end).
         let (mut starts, mut ends): (Vec<_>, Vec<_>) = info
             .0
-            .into_iter()
-            .flat_map(|(kind, ranges)| ranges.into_iter().map(move |(lo, hi)| ((lo, kind), hi)))
+            .iter()
+            .flat_map(|(&kind, ranges)| ranges.into_iter().map(move |&(lo, hi)| ((lo, kind), hi)))
             .unzip();
 
         // Sort the sequences in document order.
@@ -542,7 +542,7 @@ struct Classifier<'src> {
 impl<'src> Classifier<'src> {
     /// Takes as argument the source code to HTML-ify, the rust edition to use and the source code
     /// file span which will be used later on by the `span_correspondence_map`.
-    fn new(src: &str, file_span: Span, decoration_info: Option<DecorationInfo>) -> Classifier<'_> {
+    fn new(src: &'src str, file_span: Span, decoration_info: Option<&DecorationInfo>) -> Self {
         let tokens = PeekIter::new(TokenIter { src, cursor: Cursor::new(src) });
         let decorations = decoration_info.map(Decorations::new);
         Classifier {
diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs
index fd5275189d6..fccbb98f80f 100644
--- a/src/librustdoc/html/highlight/tests.rs
+++ b/src/librustdoc/html/highlight/tests.rs
@@ -78,7 +78,7 @@ let a = 4;";
         decorations.insert("example2", vec![(22, 32)]);
 
         let mut html = Buffer::new();
-        write_code(&mut html, src, None, Some(DecorationInfo(decorations)));
+        write_code(&mut html, src, None, Some(&DecorationInfo(decorations)));
         expect_file!["fixtures/decorations.html"].assert_eq(&html.into_inner());
     });
 }
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 9a9ce31caaa..a27a9d202eb 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -69,9 +69,9 @@ use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
 use crate::html::escape::Escape;
 use crate::html::format::{
-    Buffer, Ending, HrefError, PrintWithSpace, display_fn, href, join_with_double_colon,
-    print_abi_with_space, print_constness_with_space, print_default_space, print_generic_bounds,
-    print_where_clause, visibility_print_with_space,
+    Buffer, Ending, HrefError, PrintWithSpace, href, join_with_double_colon, print_abi_with_space,
+    print_constness_with_space, print_default_space, print_generic_bounds, print_where_clause,
+    visibility_print_with_space,
 };
 use crate::html::markdown::{
     HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine,
@@ -82,13 +82,14 @@ use crate::scrape_examples::{CallData, CallLocation};
 use crate::{DOC_RUST_LANG_ORG_CHANNEL, try_none};
 
 pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ {
-    crate::html::format::display_fn(move |f| {
+    fmt::from_fn(move |f| {
         if !v.ends_with('/') && !v.is_empty() { write!(f, "{v}/") } else { f.write_str(v) }
     })
 }
 
 /// Specifies whether rendering directly implemented trait items or ones from a certain Deref
 /// impl.
+#[derive(Copy, Clone)]
 pub(crate) enum AssocItemRender<'a> {
     All,
     DerefFor { trait_: &'a clean::Path, type_: &'a clean::Type, deref_mut_: bool },
@@ -309,9 +310,7 @@ impl ItemEntry {
 
 impl ItemEntry {
     pub(crate) fn print(&self) -> impl fmt::Display + '_ {
-        crate::html::format::display_fn(move |f| {
-            write!(f, "<a href=\"{}\">{}</a>", self.url, Escape(&self.name))
-        })
+        fmt::from_fn(move |f| write!(f, "<a href=\"{}\">{}</a>", self.url, Escape(&self.name)))
     }
 }
 
@@ -513,7 +512,7 @@ fn document<'a, 'cx: 'a>(
         info!("Documenting {name}");
     }
 
-    display_fn(move |f| {
+    fmt::from_fn(move |f| {
         document_item_info(cx, item, parent).render_into(f).unwrap();
         if parent.is_none() {
             write!(f, "{}", document_full_collapsible(item, cx, heading_offset))
@@ -530,7 +529,7 @@ fn render_markdown<'a, 'cx: 'a>(
     links: Vec<RenderedLink>,
     heading_offset: HeadingOffset,
 ) -> impl fmt::Display + 'a + Captures<'cx> {
-    display_fn(move |f| {
+    fmt::from_fn(move |f| {
         write!(
             f,
             "<div class=\"docblock\">{}</div>",
@@ -557,7 +556,7 @@ fn document_short<'a, 'cx: 'a>(
     parent: &'a clean::Item,
     show_def_docs: bool,
 ) -> impl fmt::Display + 'a + Captures<'cx> {
-    display_fn(move |f| {
+    fmt::from_fn(move |f| {
         document_item_info(cx, item, Some(parent)).render_into(f).unwrap();
         if !show_def_docs {
             return Ok(());
@@ -605,7 +604,7 @@ fn document_full_inner<'a, 'cx: 'a>(
     is_collapsible: bool,
     heading_offset: HeadingOffset,
 ) -> impl fmt::Display + 'a + Captures<'cx> {
-    display_fn(move |f| {
+    fmt::from_fn(move |f| {
         if let Some(s) = item.opt_doc_value() {
             debug!("Doc block: =====\n{s}\n=====");
             if is_collapsible {
@@ -1159,7 +1158,7 @@ fn render_attributes_in_pre<'a, 'tcx: 'a>(
     prefix: &'a str,
     cx: &'a Context<'tcx>,
 ) -> impl fmt::Display + Captures<'a> + Captures<'tcx> {
-    crate::html::format::display_fn(move |f| {
+    fmt::from_fn(move |f| {
         for a in it.attributes(cx.tcx(), cx.cache(), false) {
             writeln!(f, "{prefix}{a}")?;
         }
@@ -1256,9 +1255,9 @@ fn render_assoc_items<'a, 'cx: 'a>(
     it: DefId,
     what: AssocItemRender<'a>,
 ) -> impl fmt::Display + 'a + Captures<'cx> {
-    let mut derefs = DefIdSet::default();
-    derefs.insert(it);
-    display_fn(move |f| {
+    fmt::from_fn(move |f| {
+        let mut derefs = DefIdSet::default();
+        derefs.insert(it);
         render_assoc_items_inner(f, cx, containing_item, it, what, &mut derefs);
         Ok(())
     })
@@ -2577,7 +2576,7 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &Context<'_>, item: &clean
             file_span,
             cx,
             &cx.root_path(),
-            highlight::DecorationInfo(decoration_info),
+            &highlight::DecorationInfo(decoration_info),
             sources::SourceContext::Embedded(sources::ScrapedInfo {
                 needs_expansion,
                 offset: line_min,
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 1376bdb2e90..37fea09ace3 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -30,7 +30,7 @@ use crate::formats::Impl;
 use crate::formats::item_type::ItemType;
 use crate::html::escape::{Escape, EscapeBodyTextWithWbr};
 use crate::html::format::{
-    Buffer, Ending, PrintWithSpace, display_fn, join_with_double_colon, print_abi_with_space,
+    Buffer, Ending, PrintWithSpace, join_with_double_colon, print_abi_with_space,
     print_constness_with_space, print_where_clause, visibility_print_with_space,
 };
 use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
@@ -92,7 +92,7 @@ macro_rules! item_template_methods {
     () => {};
     (document $($rest:tt)*) => {
         fn document<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
-            display_fn(move |f| {
+            fmt::from_fn(move |f| {
                 let (item, cx) = self.item_and_cx();
                 let v = document(cx, item, None, HeadingOffset::H2);
                 write!(f, "{v}")
@@ -102,7 +102,7 @@ macro_rules! item_template_methods {
     };
     (document_type_layout $($rest:tt)*) => {
         fn document_type_layout<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
-            display_fn(move |f| {
+            fmt::from_fn(move |f| {
                 let (item, cx) = self.item_and_cx();
                 let def_id = item.item_id.expect_def_id();
                 let v = document_type_layout(cx, def_id);
@@ -113,7 +113,7 @@ macro_rules! item_template_methods {
     };
     (render_attributes_in_pre $($rest:tt)*) => {
         fn render_attributes_in_pre<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
-            display_fn(move |f| {
+            fmt::from_fn(move |f| {
                 let (item, cx) = self.item_and_cx();
                 let v = render_attributes_in_pre(item, "", cx);
                 write!(f, "{v}")
@@ -123,7 +123,7 @@ macro_rules! item_template_methods {
     };
     (render_assoc_items $($rest:tt)*) => {
         fn render_assoc_items<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
-            display_fn(move |f| {
+            fmt::from_fn(move |f| {
                 let (item, cx) = self.item_and_cx();
                 let def_id = item.item_id.expect_def_id();
                 let v = render_assoc_items(cx, item, def_id, AssocItemRender::All);
@@ -140,10 +140,9 @@ macro_rules! item_template_methods {
     };
 }
 
-const ITEM_TABLE_OPEN: &str = "<ul class=\"item-table\">";
-const ITEM_TABLE_CLOSE: &str = "</ul>";
-const ITEM_TABLE_ROW_OPEN: &str = "<li>";
-const ITEM_TABLE_ROW_CLOSE: &str = "</li>";
+const ITEM_TABLE_OPEN: &str = "<dl class=\"item-table\">";
+const REEXPORTS_TABLE_OPEN: &str = "<dl class=\"item-table reexports\">";
+const ITEM_TABLE_CLOSE: &str = "</dl>";
 
 // A component in a `use` path, like `string` in std::string::ToString
 struct PathComponent {
@@ -400,37 +399,32 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
                 w.write_str(ITEM_TABLE_CLOSE);
             }
             last_section = Some(my_section);
-            write_section_heading(
-                w,
-                my_section.name(),
-                &cx.derive_id(my_section.id()),
-                None,
-                ITEM_TABLE_OPEN,
-            );
+            let section_id = my_section.id();
+            let tag =
+                if section_id == "reexports" { REEXPORTS_TABLE_OPEN } else { ITEM_TABLE_OPEN };
+            write_section_heading(w, my_section.name(), &cx.derive_id(section_id), None, tag);
         }
 
         match myitem.kind {
             clean::ExternCrateItem { ref src } => {
                 use crate::html::format::anchor;
 
-                w.write_str(ITEM_TABLE_ROW_OPEN);
                 match *src {
                     Some(src) => write!(
                         w,
-                        "<div class=\"item-name\"><code>{}extern crate {} as {};",
+                        "<dt><code>{}extern crate {} as {};",
                         visibility_print_with_space(myitem, cx),
                         anchor(myitem.item_id.expect_def_id(), src, cx),
                         EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()),
                     ),
                     None => write!(
                         w,
-                        "<div class=\"item-name\"><code>{}extern crate {};",
+                        "<dt><code>{}extern crate {};",
                         visibility_print_with_space(myitem, cx),
                         anchor(myitem.item_id.expect_def_id(), myitem.name.unwrap(), cx),
                     ),
                 }
-                w.write_str("</code></div>");
-                w.write_str(ITEM_TABLE_ROW_CLOSE);
+                w.write_str("</code></dt>");
             }
 
             clean::ImportItem(ref import) => {
@@ -438,28 +432,20 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
                     extra_info_tags(tcx, myitem, item, Some(import_def_id)).to_string()
                 });
 
-                w.write_str(ITEM_TABLE_ROW_OPEN);
                 let id = match import.kind {
                     clean::ImportKind::Simple(s) => {
                         format!(" id=\"{}\"", cx.derive_id(format!("reexport.{s}")))
                     }
                     clean::ImportKind::Glob => String::new(),
                 };
-                let (stab_tags_before, stab_tags_after) = if stab_tags.is_empty() {
-                    ("", "")
-                } else {
-                    ("<div class=\"desc docblock-short\">", "</div>")
-                };
                 write!(
                     w,
-                    "<div class=\"item-name\"{id}>\
-                         <code>{vis}{imp}</code>\
-                     </div>\
-                     {stab_tags_before}{stab_tags}{stab_tags_after}",
+                    "<dt{id}>\
+                         <code>{vis}{imp}</code>{stab_tags}\
+                     </dt>",
                     vis = visibility_print_with_space(myitem, cx),
                     imp = import.print(cx),
                 );
-                w.write_str(ITEM_TABLE_ROW_CLOSE);
             }
 
             _ => {
@@ -492,22 +478,18 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
                     _ => "",
                 };
 
-                w.write_str(ITEM_TABLE_ROW_OPEN);
                 let docs =
                     MarkdownSummaryLine(&myitem.doc_value(), &myitem.links(cx)).into_string();
-                let (docs_before, docs_after) = if docs.is_empty() {
-                    ("", "")
-                } else {
-                    ("<div class=\"desc docblock-short\">", "</div>")
-                };
+                let (docs_before, docs_after) =
+                    if docs.is_empty() { ("", "") } else { ("<dd>", "</dd>") };
                 write!(
                     w,
-                    "<div class=\"item-name\">\
+                    "<dt>\
                         <a class=\"{class}\" href=\"{href}\" title=\"{title}\">{name}</a>\
                         {visibility_and_hidden}\
                         {unsafety_flag}\
                         {stab_tags}\
-                     </div>\
+                     </dt>\
                      {docs_before}{docs}{docs_after}",
                     name = EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()),
                     visibility_and_hidden = visibility_and_hidden,
@@ -521,7 +503,6 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
                         .collect::<Vec<_>>()
                         .join(" "),
                 );
-                w.write_str(ITEM_TABLE_ROW_CLOSE);
             }
         }
     }
@@ -539,13 +520,13 @@ fn extra_info_tags<'a, 'tcx: 'a>(
     parent: &'a clean::Item,
     import_def_id: Option<DefId>,
 ) -> impl fmt::Display + 'a + Captures<'tcx> {
-    display_fn(move |f| {
+    fmt::from_fn(move |f| {
         fn tag_html<'a>(
             class: &'a str,
             title: &'a str,
             contents: &'a str,
         ) -> impl fmt::Display + 'a {
-            display_fn(move |f| {
+            fmt::from_fn(move |f| {
                 write!(
                     f,
                     r#"<wbr><span class="stab {class}" title="{title}">{contents}</span>"#,
@@ -933,7 +914,6 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
     let mut extern_crates = FxIndexSet::default();
 
     if !t.is_dyn_compatible(cx.tcx()) {
-        // FIXME(dyn_compat_renaming): Update the URL once the Reference is updated.
         write_section_heading(
             w,
             "Dyn Compatibility",
@@ -941,7 +921,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
             None,
             format!(
                 "<div class=\"dyn-compatibility-info\"><p>This trait is <b>not</b> \
-                <a href=\"{base}/reference/items/traits.html#object-safety\">dyn compatible</a>.</p>\
+                <a href=\"{base}/reference/items/traits.html#dyn-compatibility\">dyn compatible</a>.</p>\
                 <p><i>In older versions of Rust, dyn compatibility was called \"object safety\", \
                 so this trait is not object safe.</i></p></div>",
                 base = crate::clean::utils::DOC_RUST_LANG_ORG_CHANNEL
@@ -1395,7 +1375,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
 
     impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> {
         fn render_union<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
-            display_fn(move |f| {
+            fmt::from_fn(move |f| {
                 let v = render_union(self.it, Some(&self.s.generics), &self.s.fields, self.cx);
                 write!(f, "{v}")
             })
@@ -1405,7 +1385,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
             &'b self,
             field: &'a clean::Item,
         ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
-            display_fn(move |f| {
+            fmt::from_fn(move |f| {
                 let v = document(self.cx, field, Some(self.it), HeadingOffset::H3);
                 write!(f, "{v}")
             })
@@ -1419,7 +1399,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
             &'b self,
             ty: &'a clean::Type,
         ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
-            display_fn(move |f| {
+            fmt::from_fn(move |f| {
                 let v = ty.print(self.cx);
                 write!(f, "{v}")
             })
@@ -1446,7 +1426,7 @@ fn print_tuple_struct_fields<'a, 'cx: 'a>(
     cx: &'a Context<'cx>,
     s: &'a [clean::Item],
 ) -> impl fmt::Display + 'a + Captures<'cx> {
-    display_fn(|f| {
+    fmt::from_fn(|f| {
         if !s.is_empty()
             && s.iter().all(|field| {
                 matches!(field.kind, clean::StrippedItem(box clean::StructFieldItem(..)))
@@ -2171,7 +2151,7 @@ fn render_union<'a, 'cx: 'a>(
     fields: &'a [clean::Item],
     cx: &'a Context<'cx>,
 ) -> impl fmt::Display + 'a + Captures<'cx> {
-    display_fn(move |mut f| {
+    fmt::from_fn(move |mut f| {
         write!(f, "{}union {}", visibility_print_with_space(it, cx), it.name.unwrap(),)?;
 
         let where_displayed = g
@@ -2351,7 +2331,7 @@ fn document_non_exhaustive_header(item: &clean::Item) -> &str {
 }
 
 fn document_non_exhaustive(item: &clean::Item) -> impl fmt::Display + '_ {
-    display_fn(|f| {
+    fmt::from_fn(|f| {
         if item.is_non_exhaustive() {
             write!(
                 f,
diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs
index 881df8b0050..23ac568fdf8 100644
--- a/src/librustdoc/html/render/sidebar.rs
+++ b/src/librustdoc/html/render/sidebar.rs
@@ -100,18 +100,17 @@ impl<'a> Link<'a> {
 }
 
 pub(crate) mod filters {
-    use std::fmt::Display;
+    use std::fmt::{self, Display};
 
     use rinja::filters::Safe;
 
     use crate::html::escape::EscapeBodyTextWithWbr;
-    use crate::html::render::display_fn;
     pub(crate) fn wrapped<T>(v: T) -> rinja::Result<Safe<impl Display>>
     where
         T: Display,
     {
         let string = v.to_string();
-        Ok(Safe(display_fn(move |f| EscapeBodyTextWithWbr(&string).fmt(f))))
+        Ok(Safe(fmt::from_fn(move |f| EscapeBodyTextWithWbr(&string).fmt(f))))
     }
 }
 
diff --git a/src/librustdoc/html/render/type_layout.rs b/src/librustdoc/html/render/type_layout.rs
index 9317844956d..0f01db5f6bc 100644
--- a/src/librustdoc/html/render/type_layout.rs
+++ b/src/librustdoc/html/render/type_layout.rs
@@ -9,7 +9,6 @@ use rustc_middle::ty::layout::LayoutError;
 use rustc_middle::ty::{self};
 use rustc_span::symbol::Symbol;
 
-use crate::html::format::display_fn;
 use crate::html::render::Context;
 
 #[derive(Template)]
@@ -31,7 +30,7 @@ pub(crate) fn document_type_layout<'a, 'cx: 'a>(
     cx: &'a Context<'cx>,
     ty_def_id: DefId,
 ) -> impl fmt::Display + 'a + Captures<'cx> {
-    display_fn(move |f| {
+    fmt::from_fn(move |f| {
         if !cx.shared.show_type_layout {
             return Ok(());
         }
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 9827f97d28d..1ac0c10c612 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -17,7 +17,7 @@ use crate::clean::utils::has_doc_flag;
 use crate::docfs::PathError;
 use crate::error::Error;
 use crate::html::render::Context;
-use crate::html::{format, highlight, layout};
+use crate::html::{highlight, layout};
 use crate::visit::DocVisitor;
 
 pub(crate) fn render(cx: &mut Context<'_>, krate: &clean::Crate) -> Result<(), Error> {
@@ -249,7 +249,7 @@ impl SourceCollector<'_, '_> {
                     file_span,
                     self.cx,
                     &root_path,
-                    highlight::DecorationInfo::default(),
+                    &highlight::DecorationInfo::default(),
                     SourceContext::Standalone { file_path },
                 )
             },
@@ -328,13 +328,13 @@ pub(crate) fn print_src(
     file_span: rustc_span::Span,
     context: &Context<'_>,
     root_path: &str,
-    decoration_info: highlight::DecorationInfo,
+    decoration_info: &highlight::DecorationInfo,
     source_context: SourceContext<'_>,
 ) {
-    let current_href = context
-        .href_from_span(clean::Span::new(file_span), false)
-        .expect("only local crates should have sources emitted");
-    let code = format::display_fn(move |fmt| {
+    let code = fmt::from_fn(move |fmt| {
+        let current_href = context
+            .href_from_span(clean::Span::new(file_span), false)
+            .expect("only local crates should have sources emitted");
         highlight::write_code(
             fmt,
             s,
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index a1ab258ff30..b994a43868c 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -242,7 +242,7 @@ h1, h2, h3, h4, h5, h6,
 .mobile-topbar,
 .search-input,
 .search-results .result-name,
-.item-name > a,
+.item-table dt > a,
 .out-of-band,
 .sub-heading,
 span.since,
@@ -385,11 +385,11 @@ details:not(.toggle) summary {
 code, pre, .code-header, .type-signature {
 	font-family: "Source Code Pro", monospace;
 }
-.docblock code, .docblock-short code {
+.docblock code, .item-table dd code {
 	border-radius: 3px;
 	padding: 0 0.125em;
 }
-.docblock pre code, .docblock-short pre code {
+.docblock pre code, .item-table dd pre code {
 	padding: 0;
 }
 pre {
@@ -887,13 +887,13 @@ both the code example and the line numbers, so we need to remove the radius in t
 	text-align: center;
 }
 
-.docblock-short {
+.item-table dd {
 	overflow-wrap: break-word;
 	overflow-wrap: anywhere;
 }
 /* Wrap non-pre code blocks (`text`) but not (```text```). */
 .docblock :not(pre) > code,
-.docblock-short code {
+.item-table dd code {
 	white-space: pre-wrap;
 }
 
@@ -938,7 +938,7 @@ rustdoc-toolbar {
 	min-height: 60px;
 }
 
-.docblock code, .docblock-short code,
+.docblock code, .item-table dd code,
 pre, .rustdoc.src .example-wrap, .example-wrap .src-line-numbers {
 	background-color: var(--code-block-background-color);
 	border-radius: var(--code-block-border-radius);
@@ -964,7 +964,7 @@ pre, .rustdoc.src .example-wrap, .example-wrap .src-line-numbers {
 	background: var(--table-alt-row-background-color);
 }
 
-.docblock .stab, .docblock-short .stab, .docblock p code {
+.docblock .stab, .item-table dd .stab, .docblock p code {
 	display: inline-block;
 }
 
@@ -1069,7 +1069,7 @@ because of the `[-]` element which would overlap with it. */
 .example-wrap .rust a:hover,
 .all-items a:hover,
 .docblock a:not(.scrape-help):not(.tooltip):hover:not(.doc-anchor),
-.docblock-short a:not(.scrape-help):not(.tooltip):hover,
+.item-table dd a:not(.scrape-help):not(.tooltip):hover,
 .item-info a {
 	text-decoration: underline;
 }
@@ -1102,20 +1102,17 @@ table,
 }
 
 .item-table {
-	display: table;
 	padding: 0;
 	margin: 0;
 	width: 100%;
 }
-.item-table > li {
-	display: table-row;
-}
-.item-table > li > div {
-	display: table-cell;
-}
-.item-table > li > .item-name {
+.item-table > dt {
 	padding-right: 1.25rem;
 }
+.item-table > dd {
+	margin-inline-start: 0;
+	margin-left: 0;
+}
 
 .search-results-title {
 	margin-top: 0;
@@ -1415,7 +1412,7 @@ so that we can apply CSS-filters to change the arrow color in themes */
 	padding: 3px;
 	margin-bottom: 5px;
 }
-.item-name .stab {
+.item-table dt .stab {
 	margin-left: 0.3125em;
 }
 .stab {
@@ -2476,7 +2473,6 @@ in src-script.js and main.js
 	}
 
 	/* Display an alternating layout on tablets and phones */
-	.item-table, .item-row, .item-table > li, .item-table > li > div,
 	.search-results > a, .search-results > a > div {
 		display: block;
 	}
@@ -2485,7 +2481,7 @@ in src-script.js and main.js
 	.search-results > a {
 		padding: 5px 0px;
 	}
-	.search-results > a > div.desc, .item-table > li > div.desc {
+	.search-results > a > div.desc, .item-table dd {
 		padding-left: 2em;
 	}
 	.search-results .result-name {
@@ -2546,12 +2542,20 @@ in src-script.js and main.js
 		box-shadow: 0 0 4px var(--main-background-color);
 	}
 
-	.item-table > li > .item-name {
-		width: 33%;
+	/* Since the screen is wide enough, we show items on their description on the same line. */
+	.item-table:not(.reexports) {
+		display: grid;
+		grid-template-columns: 33% 67%;
 	}
-	.item-table > li > div {
+	.item-table > dt, .item-table > dd {
 		overflow-wrap: anywhere;
 	}
+	.item-table > dt {
+		grid-column-start: 1;
+	}
+	.item-table > dd {
+		grid-column-start: 2;
+	}
 }
 
 @media print {
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index ba620b6cb6b..bb954a31891 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -5,6 +5,7 @@
 #![feature(rustc_private)]
 #![feature(assert_matches)]
 #![feature(box_patterns)]
+#![feature(debug_closure_helpers)]
 #![feature(file_buffered)]
 #![feature(if_let_guard)]
 #![feature(impl_trait_in_assoc_type)]
@@ -73,8 +74,6 @@ extern crate tikv_jemalloc_sys as jemalloc_sys;
 use std::env::{self, VarError};
 use std::io::{self, IsTerminal};
 use std::process;
-use std::sync::Arc;
-use std::sync::atomic::AtomicBool;
 
 use rustc_errors::DiagCtxtHandle;
 use rustc_interface::interface;
@@ -158,7 +157,7 @@ pub fn main() {
 
     let mut early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
 
-    let using_internal_features = rustc_driver::install_ice_hook(
+    rustc_driver::install_ice_hook(
         "https://github.com/rust-lang/rust/issues/new\
     ?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md",
         |_| (),
@@ -179,7 +178,7 @@ pub fn main() {
 
     let exit_code = rustc_driver::catch_with_exit_code(|| {
         let at_args = rustc_driver::args::raw_args(&early_dcx)?;
-        main_args(&mut early_dcx, &at_args, using_internal_features);
+        main_args(&mut early_dcx, &at_args);
         Ok(())
     });
     process::exit(exit_code);
@@ -768,11 +767,7 @@ fn run_merge_finalize(opt: config::RenderOptions) -> Result<(), error::Error> {
     Ok(())
 }
 
-fn main_args(
-    early_dcx: &mut EarlyDiagCtxt,
-    at_args: &[String],
-    using_internal_features: Arc<AtomicBool>,
-) {
+fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
     // Throw away the first argument, the name of the binary.
     // In case of at_args being empty, as might be the case by
     // passing empty argument array to execve under some platforms,
@@ -825,8 +820,7 @@ fn main_args(
         (false, Some(md_input)) => {
             let md_input = md_input.to_owned();
             let edition = options.edition;
-            let config =
-                core::create_config(input, options, &render_options, using_internal_features);
+            let config = core::create_config(input, options, &render_options);
 
             // `markdown::render` can invoke `doctest::make_test`, which
             // requires session globals and a thread pool, so we use
@@ -859,7 +853,7 @@ fn main_args(
     let scrape_examples_options = options.scrape_examples_options.clone();
     let bin_crate = options.bin_crate;
 
-    let config = core::create_config(input, options, &render_options, using_internal_features);
+    let config = core::create_config(input, options, &render_options);
 
     let registered_lints = config.register_lints.is_some();
 
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 5a99977ded5..916f0ab3cc8 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -1099,8 +1099,7 @@ pub struct Trait {
     pub is_auto: bool,
     /// Whether the trait is marked as `unsafe`.
     pub is_unsafe: bool,
-    // FIXME(dyn_compat_renaming): Update the URL once the Reference is updated and hits stable.
-    /// Whether the trait is [dyn compatible](https://doc.rust-lang.org/reference/items/traits.html#object-safety)[^1].
+    /// Whether the trait is [dyn compatible](https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility)[^1].
     ///
     /// [^1]: Formerly known as "object safe".
     pub is_dyn_compatible: bool,
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 5418acc105e..26bea8d633a 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -18,6 +18,7 @@ use rustc_session::declare_lint_pass;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol};
+use rustc_trait_selection::traits::supertrait_def_ids;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -270,7 +271,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items
     // fill the set with current and super traits
     fn fill_trait_set(traitt: DefId, set: &mut DefIdSet, cx: &LateContext<'_>) {
         if set.insert(traitt) {
-            for supertrait in cx.tcx.supertrait_def_ids(traitt) {
+            for supertrait in supertrait_def_ids(cx.tcx, traitt) {
                 fill_trait_set(supertrait, set, cx);
             }
         }
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 428b40c5771..104ae154e36 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -109,7 +109,7 @@ fn check_rvalue<'tcx>(
 ) -> McfResult {
     match rvalue {
         Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())),
-        Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::RawPtr(_, place) => {
+        Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::RawPtr(_, place) => {
             check_place(tcx, *place, span, body, msrv)
         },
         Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body, msrv),
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 75ef60a5dc8..68edefd3095 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -186,7 +186,7 @@ pub fn main() {
 
     rustc_driver::init_rustc_env_logger(&early_dcx);
 
-    let using_internal_features = rustc_driver::install_ice_hook(BUG_REPORT_URL, |dcx| {
+    rustc_driver::install_ice_hook(BUG_REPORT_URL, |dcx| {
         // FIXME: this macro calls unwrap internally but is called in a panicking context!  It's not
         // as simple as moving the call from the hook to main, because `install_ice_hook` doesn't
         // accept a generic closure.
@@ -236,7 +236,7 @@ pub fn main() {
             let mut args: Vec<String> = orig_args.clone();
             pass_sysroot_env_if_given(&mut args, sys_root_env);
 
-            rustc_driver::RunCompiler::new(&args, &mut DefaultCallbacks).run();
+            rustc_driver::run_compiler(&args, &mut DefaultCallbacks);
             return Ok(());
         }
 
@@ -295,13 +295,9 @@ pub fn main() {
         let clippy_enabled = !cap_lints_allow && relevant_package && !info_query;
         if clippy_enabled {
             args.extend(clippy_args);
-            rustc_driver::RunCompiler::new(&args, &mut ClippyCallbacks { clippy_args_var })
-                .set_using_internal_features(using_internal_features)
-                .run();
+            rustc_driver::run_compiler(&args, &mut ClippyCallbacks { clippy_args_var });
         } else {
-            rustc_driver::RunCompiler::new(&args, &mut RustcCallbacks { clippy_args_var })
-                .set_using_internal_features(using_internal_features)
-                .run();
+            rustc_driver::run_compiler(&args, &mut RustcCallbacks { clippy_args_var });
         }
         Ok(())
     }))
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed
index f66554de300..26c6a5033d1 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed
@@ -1,10 +1,9 @@
 #![warn(clippy::borrow_as_ptr)]
-#![feature(lang_items, start, libc)]
 #![no_std]
+#![crate_type = "lib"]
 
 #[clippy::msrv = "1.75"]
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
     let val = 1;
     let _p = core::ptr::addr_of!(val);
 
@@ -12,11 +11,3 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
     let _p_mut = core::ptr::addr_of_mut!(val_mut);
     0
 }
-
-#[panic_handler]
-fn panic(_info: &core::panic::PanicInfo) -> ! {
-    loop {}
-}
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs
index 1fc254aafa7..d8d8b4c380c 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs
@@ -1,10 +1,9 @@
 #![warn(clippy::borrow_as_ptr)]
-#![feature(lang_items, start, libc)]
 #![no_std]
+#![crate_type = "lib"]
 
 #[clippy::msrv = "1.75"]
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
     let val = 1;
     let _p = &val as *const i32;
 
@@ -12,11 +11,3 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
     let _p_mut = &mut val_mut as *mut i32;
     0
 }
-
-#[panic_handler]
-fn panic(_info: &core::panic::PanicInfo) -> ! {
-    loop {}
-}
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr
index 6802c86ec95..488e0bd9677 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr
@@ -1,5 +1,5 @@
 error: borrow as raw pointer
-  --> tests/ui/borrow_as_ptr_no_std.rs:9:14
+  --> tests/ui/borrow_as_ptr_no_std.rs:8:14
    |
 LL |     let _p = &val as *const i32;
    |              ^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::addr_of!(val)`
@@ -8,7 +8,7 @@ LL |     let _p = &val as *const i32;
    = help: to override `-D warnings` add `#[allow(clippy::borrow_as_ptr)]`
 
 error: borrow as raw pointer
-  --> tests/ui/borrow_as_ptr_no_std.rs:12:18
+  --> tests/ui/borrow_as_ptr_no_std.rs:11:18
    |
 LL |     let _p_mut = &mut val_mut as *mut i32;
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::addr_of_mut!(val_mut)`
diff --git a/src/tools/clippy/tests/ui/box_default_no_std.rs b/src/tools/clippy/tests/ui/box_default_no_std.rs
index 4326abc9a54..edb701fcd08 100644
--- a/src/tools/clippy/tests/ui/box_default_no_std.rs
+++ b/src/tools/clippy/tests/ui/box_default_no_std.rs
@@ -1,6 +1,6 @@
-#![feature(lang_items, start, libc)]
 #![warn(clippy::box_default)]
 #![no_std]
+#![crate_type = "lib"]
 
 pub struct NotBox<T> {
     _value: T,
@@ -18,16 +18,7 @@ impl<T: Default> Default for NotBox<T> {
     }
 }
 
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
     let _p = NotBox::new(isize::default());
     0
 }
-
-#[panic_handler]
-fn panic(_info: &core::panic::PanicInfo) -> ! {
-    loop {}
-}
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-7410.rs b/src/tools/clippy/tests/ui/crashes/ice-7410.rs
index ccf6d7ff94f..addbca54e80 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-7410.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-7410.rs
@@ -1,7 +1,7 @@
 //@compile-flags: -Clink-arg=-nostartfiles
 //@ignore-target: apple windows
 
-#![feature(lang_items, start, libc)]
+#![crate_type = "lib"]
 #![no_std]
 #![allow(clippy::if_same_then_else)]
 #![allow(clippy::redundant_pattern_matching)]
@@ -15,18 +15,9 @@ impl Drop for S {
     fn drop(&mut self) {}
 }
 
-#[start]
-fn main(argc: isize, argv: *const *const u8) -> isize {
+pub fn main(argc: isize, argv: *const *const u8) -> isize {
     if let Some(_) = Some(S) {
     } else {
     }
     0
 }
-
-#[panic_handler]
-fn panic(_info: &PanicInfo) -> ! {
-    loop {}
-}
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/crate_level_checks/no_std_main_recursion.rs b/src/tools/clippy/tests/ui/crate_level_checks/no_std_main_recursion.rs
deleted file mode 100644
index 9e5b2a48903..00000000000
--- a/src/tools/clippy/tests/ui/crate_level_checks/no_std_main_recursion.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-//@compile-flags: -Clink-arg=-nostartfiles
-//@ignore-target: apple
-
-#![feature(lang_items, start, libc)]
-#![no_std]
-
-use core::panic::PanicInfo;
-use core::sync::atomic::{AtomicUsize, Ordering};
-
-static N: AtomicUsize = AtomicUsize::new(0);
-
-#[warn(clippy::main_recursion)]
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
-    let x = N.load(Ordering::Relaxed);
-    N.store(x + 1, Ordering::Relaxed);
-
-    if x < 3 {
-        main(_argc, _argv);
-    }
-
-    0
-}
-
-#[allow(clippy::empty_loop)]
-#[panic_handler]
-fn panic(_info: &PanicInfo) -> ! {
-    loop {}
-}
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.fixed b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.fixed
index 32bccd3a0ff..e09a913ef06 100644
--- a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.fixed
+++ b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.fixed
@@ -1,11 +1,10 @@
 #![no_std]
-#![feature(lang_items, start, libc)]
 #![crate_type = "lib"]
 
 use core::panic::PanicInfo;
 
 #[warn(clippy::all)]
-fn main() {
+pub fn main() {
     let mut a = 42;
     let mut b = 1337;
 
diff --git a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs
index 8ed45a33465..536e71b4a25 100644
--- a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs
+++ b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs
@@ -1,11 +1,10 @@
 #![no_std]
-#![feature(lang_items, start, libc)]
 #![crate_type = "lib"]
 
 use core::panic::PanicInfo;
 
 #[warn(clippy::all)]
-fn main() {
+pub fn main() {
     let mut a = 42;
     let mut b = 1337;
 
diff --git a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr
index bcc8684f7c2..3e37bd95ef3 100644
--- a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr
+++ b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr
@@ -1,5 +1,5 @@
 error: this looks like you are trying to swap `a` and `b`
-  --> tests/ui/crate_level_checks/no_std_swap.rs:12:5
+  --> tests/ui/crate_level_checks/no_std_swap.rs:11:5
    |
 LL | /     a = b;
 ...  |
diff --git a/src/tools/clippy/tests/ui/def_id_nocore.rs b/src/tools/clippy/tests/ui/def_id_nocore.rs
index c9650312db8..03f5ca31f5f 100644
--- a/src/tools/clippy/tests/ui/def_id_nocore.rs
+++ b/src/tools/clippy/tests/ui/def_id_nocore.rs
@@ -1,6 +1,6 @@
 //@ignore-target: apple
 
-#![feature(no_core, lang_items, start)]
+#![feature(no_core, lang_items)]
 #![no_core]
 #![allow(clippy::missing_safety_doc)]
 
diff --git a/src/tools/clippy/tests/ui/empty_loop_no_std.rs b/src/tools/clippy/tests/ui/empty_loop_no_std.rs
index 1bb895bda75..9bfcbfba969 100644
--- a/src/tools/clippy/tests/ui/empty_loop_no_std.rs
+++ b/src/tools/clippy/tests/ui/empty_loop_no_std.rs
@@ -2,27 +2,11 @@
 //@ignore-target: apple
 
 #![warn(clippy::empty_loop)]
-#![feature(lang_items, start, libc)]
+#![crate_type = "lib"]
 #![no_std]
 
-use core::panic::PanicInfo;
-
-#[start]
-fn main(argc: isize, argv: *const *const u8) -> isize {
+pub fn main(argc: isize, argv: *const *const u8) -> isize {
     // This should trigger the lint
     loop {}
     //~^ ERROR: empty `loop {}` wastes CPU cycles
 }
-
-#[panic_handler]
-fn panic(_info: &PanicInfo) -> ! {
-    // This should NOT trigger the lint
-    loop {}
-}
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {
-    // This should also trigger the lint
-    loop {}
-    //~^ ERROR: empty `loop {}` wastes CPU cycles
-}
diff --git a/src/tools/clippy/tests/ui/empty_loop_no_std.stderr b/src/tools/clippy/tests/ui/empty_loop_no_std.stderr
index f4a18204c3c..f36fb9d9e3f 100644
--- a/src/tools/clippy/tests/ui/empty_loop_no_std.stderr
+++ b/src/tools/clippy/tests/ui/empty_loop_no_std.stderr
@@ -1,5 +1,5 @@
 error: empty `loop {}` wastes CPU cycles
-  --> tests/ui/empty_loop_no_std.rs:13:5
+  --> tests/ui/empty_loop_no_std.rs:10:5
    |
 LL |     loop {}
    |     ^^^^^^^
@@ -8,13 +8,5 @@ LL |     loop {}
    = note: `-D clippy::empty-loop` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::empty_loop)]`
 
-error: empty `loop {}` wastes CPU cycles
-  --> tests/ui/empty_loop_no_std.rs:26:5
-   |
-LL |     loop {}
-   |     ^^^^^^^
-   |
-   = help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
diff --git a/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs b/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs
index 8ea75fae89b..81e4e0380da 100644
--- a/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs
+++ b/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs
@@ -1,4 +1,4 @@
-#![feature(lang_items, start)]
+#![crate_type = "lib"]
 #![warn(clippy::imprecise_flops)]
 #![warn(clippy::suboptimal_flops)]
 #![no_std]
@@ -17,15 +17,6 @@ fn fake_abs1(num: f64) -> f64 {
     if num >= 0.0 { num } else { -num }
 }
 
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
     0
 }
-
-#[panic_handler]
-fn panic(_info: &core::panic::PanicInfo) -> ! {
-    loop {}
-}
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
index d2f9e34a5ce..fdde68790a8 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
@@ -6,7 +6,6 @@
 //@aux-build:../auxiliary/proc_macros.rs
 
 #![warn(clippy::missing_const_for_fn)]
-#![feature(start)]
 #![feature(type_alias_impl_trait)]
 
 extern crate helper;
@@ -71,15 +70,6 @@ mod with_test_fn {
     }
 }
 
-// Allowing on this function, because it would lint, which we don't want in this case.
-// if we have `#[start]` and `#[test]` check `is_entrypoint_fn(cx, def_id.to_def_id())` is stopped
-// working
-#[allow(clippy::missing_const_for_fn)]
-#[start]
-fn init(num: isize, something: *const *const u8) -> isize {
-    1
-}
-
 trait Foo {
     // This should not be suggested to be made const
     // (rustc doesn't allow const trait methods)
diff --git a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.fixed b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.fixed
index 497e0e24317..771ab1ab21a 100644
--- a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.fixed
+++ b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.fixed
@@ -1,22 +1,13 @@
 #![warn(clippy::missing_spin_loop)]
-#![feature(lang_items, start, libc)]
+#![crate_type = "lib"]
 #![no_std]
 
 use core::sync::atomic::{AtomicBool, Ordering};
 
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
     // This should trigger the lint
     let b = AtomicBool::new(true);
     // This should lint with `core::hint::spin_loop()`
     while b.load(Ordering::Acquire) { core::hint::spin_loop() }
     0
 }
-
-#[panic_handler]
-fn panic(_info: &core::panic::PanicInfo) -> ! {
-    loop {}
-}
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.rs b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.rs
index 1c85a9c58d6..bf890fc4066 100644
--- a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.rs
+++ b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.rs
@@ -1,22 +1,13 @@
 #![warn(clippy::missing_spin_loop)]
-#![feature(lang_items, start, libc)]
+#![crate_type = "lib"]
 #![no_std]
 
 use core::sync::atomic::{AtomicBool, Ordering};
 
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
     // This should trigger the lint
     let b = AtomicBool::new(true);
     // This should lint with `core::hint::spin_loop()`
     while b.load(Ordering::Acquire) {}
     0
 }
-
-#[panic_handler]
-fn panic(_info: &core::panic::PanicInfo) -> ! {
-    loop {}
-}
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.stderr b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.stderr
index 7911620d32c..d4b9485be46 100644
--- a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.stderr
+++ b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.stderr
@@ -1,5 +1,5 @@
 error: busy-waiting loop should at least have a spin loop hint
-  --> tests/ui/missing_spin_loop_no_std.rs:12:37
+  --> tests/ui/missing_spin_loop_no_std.rs:11:37
    |
 LL |     while b.load(Ordering::Acquire) {}
    |                                     ^^ help: try: `{ core::hint::spin_loop() }`
diff --git a/src/tools/clippy/tests/ui/result_unit_error_no_std.rs b/src/tools/clippy/tests/ui/result_unit_error_no_std.rs
index 1e7a028a7fc..c9f4996c368 100644
--- a/src/tools/clippy/tests/ui/result_unit_error_no_std.rs
+++ b/src/tools/clippy/tests/ui/result_unit_error_no_std.rs
@@ -1,5 +1,6 @@
-#![feature(lang_items, start, libc)]
+#![feature(lang_items, libc)]
 #![no_std]
+#![no_main]
 #![warn(clippy::result_unit_err)]
 
 #[clippy::msrv = "1.80"]
@@ -12,8 +13,8 @@ pub fn returns_unit_error_lint() -> Result<u32, ()> {
     Err(())
 }
 
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int {
     0
 }
 
diff --git a/src/tools/clippy/tests/ui/result_unit_error_no_std.stderr b/src/tools/clippy/tests/ui/result_unit_error_no_std.stderr
index 33692e60554..a7807f089ab 100644
--- a/src/tools/clippy/tests/ui/result_unit_error_no_std.stderr
+++ b/src/tools/clippy/tests/ui/result_unit_error_no_std.stderr
@@ -1,5 +1,5 @@
 error: this returns a `Result<_, ()>`
-  --> tests/ui/result_unit_error_no_std.rs:11:1
+  --> tests/ui/result_unit_error_no_std.rs:12:1
    |
 LL | pub fn returns_unit_error_lint() -> Result<u32, ()> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed b/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed
index 4f4d19e883d..25143eee8cc 100644
--- a/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed
+++ b/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed
@@ -1,19 +1,10 @@
-#![feature(lang_items, start, libc)]
+#![crate_type = "lib"]
 #![no_std]
 #![deny(clippy::zero_ptr)]
 
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
     let _ = core::ptr::null::<usize>();
     let _ = core::ptr::null_mut::<f64>();
     let _: *const u8 = core::ptr::null();
     0
 }
-
-#[panic_handler]
-fn panic(_info: &core::panic::PanicInfo) -> ! {
-    loop {}
-}
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/zero_ptr_no_std.rs b/src/tools/clippy/tests/ui/zero_ptr_no_std.rs
index 54954d8d13f..965733b45d9 100644
--- a/src/tools/clippy/tests/ui/zero_ptr_no_std.rs
+++ b/src/tools/clippy/tests/ui/zero_ptr_no_std.rs
@@ -1,19 +1,10 @@
-#![feature(lang_items, start, libc)]
+#![crate_type = "lib"]
 #![no_std]
 #![deny(clippy::zero_ptr)]
 
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
+pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
     let _ = 0 as *const usize;
     let _ = 0 as *mut f64;
     let _: *const u8 = 0 as *const _;
     0
 }
-
-#[panic_handler]
-fn panic(_info: &core::panic::PanicInfo) -> ! {
-    loop {}
-}
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/zero_ptr_no_std.stderr b/src/tools/clippy/tests/ui/zero_ptr_no_std.stderr
index 42a1a41ca94..014bf312bf3 100644
--- a/src/tools/clippy/tests/ui/zero_ptr_no_std.stderr
+++ b/src/tools/clippy/tests/ui/zero_ptr_no_std.stderr
@@ -1,5 +1,5 @@
 error: `0 as *const _` detected
-  --> tests/ui/zero_ptr_no_std.rs:7:13
+  --> tests/ui/zero_ptr_no_std.rs:6:13
    |
 LL |     let _ = 0 as *const usize;
    |             ^^^^^^^^^^^^^^^^^ help: try: `core::ptr::null::<usize>()`
@@ -11,13 +11,13 @@ LL | #![deny(clippy::zero_ptr)]
    |         ^^^^^^^^^^^^^^^^
 
 error: `0 as *mut _` detected
-  --> tests/ui/zero_ptr_no_std.rs:8:13
+  --> tests/ui/zero_ptr_no_std.rs:7:13
    |
 LL |     let _ = 0 as *mut f64;
    |             ^^^^^^^^^^^^^ help: try: `core::ptr::null_mut::<f64>()`
 
 error: `0 as *const _` detected
-  --> tests/ui/zero_ptr_no_std.rs:9:24
+  --> tests/ui/zero_ptr_no_std.rs:8:24
    |
 LL |     let _: *const u8 = 0 as *const _;
    |                        ^^^^^^^^^^^^^ help: try: `core::ptr::null()`
diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml
index 16cc1d2a565..4f8e475e762 100644
--- a/src/tools/compiletest/Cargo.toml
+++ b/src/tools/compiletest/Cargo.toml
@@ -34,7 +34,7 @@ libc = "0.2"
 miow = "0.6"
 
 [target.'cfg(windows)'.dependencies.windows]
-version = "0.57.0"
+version = "0.59.0"
 features = [
     "Win32_Foundation",
     "Win32_System_Diagnostics_Debug",
diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs
index 01068af3e8c..5784cd83119 100644
--- a/src/tools/compiletest/src/directive-list.rs
+++ b/src/tools/compiletest/src/directive-list.rs
@@ -175,6 +175,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "only-beta",
     "only-bpf",
     "only-cdb",
+    "only-dist",
     "only-gnu",
     "only-i686-pc-windows-gnu",
     "only-i686-pc-windows-msvc",
diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs
index efe758e65cf..37ef63ae42e 100644
--- a/src/tools/compiletest/src/errors.rs
+++ b/src/tools/compiletest/src/errors.rs
@@ -101,6 +101,8 @@ pub fn load_errors(testfile: &Path, revision: Option<&str>) -> Vec<Error> {
 
     rdr.lines()
         .enumerate()
+        // We want to ignore utf-8 failures in tests during collection of annotations.
+        .filter(|(_, line)| line.is_ok())
         .filter_map(|(line_num, line)| {
             parse_expected(last_nonfollow_error, line_num + 1, &line.unwrap(), revision).map(
                 |(which, error)| {
diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs
index 3f7225195ce..6e5ced17c20 100644
--- a/src/tools/compiletest/src/header/cfg.rs
+++ b/src/tools/compiletest/src/header/cfg.rs
@@ -235,6 +235,12 @@ fn parse_cfg_name_directive<'a>(
         message: "when the test mode is {name}",
     }
 
+    condition! {
+        name: "dist",
+        condition: std::env::var("COMPILETEST_ENABLE_DIST_TESTS") == Ok("1".to_string()),
+        message: "when performing tests on dist toolchain"
+    }
+
     if prefix == "ignore" && outcome == MatchOutcome::Invalid {
         // Don't error out for ignore-tidy-* diretives, as those are not handled by compiletest.
         if name.starts_with("tidy-") {
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 84f2149dbdf..ca48abda5fc 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -59,7 +59,7 @@ fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R {
     use std::sync::Mutex;
 
     use windows::Win32::System::Diagnostics::Debug::{
-        SEM_FAILCRITICALERRORS, SEM_NOGPFAULTERRORBOX, SetErrorMode, THREAD_ERROR_MODE,
+        SEM_FAILCRITICALERRORS, SEM_NOGPFAULTERRORBOX, SetErrorMode,
     };
 
     static LOCK: Mutex<()> = Mutex::new(());
@@ -80,7 +80,6 @@ fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R {
     unsafe {
         // read inherited flags
         let old_mode = SetErrorMode(SEM_NOGPFAULTERRORBOX | SEM_FAILCRITICALERRORS);
-        let old_mode = THREAD_ERROR_MODE(old_mode);
         SetErrorMode(old_mode | SEM_NOGPFAULTERRORBOX | SEM_FAILCRITICALERRORS);
         let r = f();
         SetErrorMode(old_mode);
diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs
index 570b2c374c0..19340b5d07a 100644
--- a/src/tools/linkchecker/main.rs
+++ b/src/tools/linkchecker/main.rs
@@ -50,6 +50,29 @@ const LINKCHECK_EXCEPTIONS: &[(&str, &[&str])] = &[
     ("alloc/slice/trait.Concat.html", &["#method.concat"]),
     ("alloc/slice/index.html", &["#method.concat", "#method.join"]),
     ("alloc/vec/struct.Vec.html", &["#method.sort_by_key", "#method.sort_by_cached_key"]),
+    ("alloc/bstr/struct.ByteStr.html", &[
+        "#method.to_ascii_uppercase",
+        "#method.to_ascii_lowercase",
+        "core/slice::sort_by_key",
+        "core\\slice::sort_by_key",
+        "#method.sort_by_cached_key",
+        "#method.sort_by_key"
+    ]),
+    ("alloc/bstr/struct.ByteString.html", &[
+        "#method.to_ascii_uppercase",
+        "#method.to_ascii_lowercase",
+        "core/slice::sort_by_key",
+        "core\\slice::sort_by_key",
+        "#method.sort_by_cached_key",
+        "#method.sort_by_key"
+    ]),
+    ("core/bstr/struct.ByteStr.html", &[
+        "#method.to_ascii_uppercase",
+        "#method.to_ascii_lowercase",
+        "core/bstr/slice::sort_by_key",
+        "core\\bstr\\slice::sort_by_key",
+        "#method.sort_by_cached_key"
+    ]),
     ("core/primitive.str.html", &["#method.to_ascii_uppercase", "#method.to_ascii_lowercase"]),
     ("core/primitive.slice.html", &["#method.to_ascii_uppercase", "#method.to_ascii_lowercase",
                                     "core/slice::sort_by_key", "core\\slice::sort_by_key",
diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml
index 209fd622202..81df0964d59 100644
--- a/src/tools/miri/.github/workflows/ci.yml
+++ b/src/tools/miri/.github/workflows/ci.yml
@@ -126,7 +126,7 @@ jobs:
         with:
           fetch-depth: 256 # get a bit more of the history
       - name: install josh-proxy
-        run: RUSTFLAGS="--cap-lints warn" cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r23.12.04
+        run: cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r24.10.04
       - name: setup bot git name and email
         run: |
           git config --global user.name 'The Miri Cronjob Bot'
diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md
index dd283b7c0a8..5a08ac9af60 100644
--- a/src/tools/miri/CONTRIBUTING.md
+++ b/src/tools/miri/CONTRIBUTING.md
@@ -290,7 +290,7 @@ We use the [`josh` proxy](https://github.com/josh-project/josh) to transmit chan
 rustc and Miri repositories. You can install it as follows:
 
 ```sh
-RUSTFLAGS="--cap-lints=warn" cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r23.12.04
+cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r24.10.04
 ```
 
 Josh will automatically be started and stopped by `./miri`.
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index 9042c5da577..4ae901be9b4 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -217,8 +217,8 @@ degree documented below):
 - For every other target with OS `linux`, `macos`, or `windows`, Miri should generally work, but we
   make no promises and we don't run tests for such targets.
 - We have unofficial support (not maintained by the Miri team itself) for some further operating systems.
-  - `solaris` / `illumos`: maintained by @devnexen. Supports `std::{env, thread, sync}`, but not `std::fs`.
-  - `freebsd`: **maintainer wanted**. Supports `std::env` and parts of `std::{thread, fs}`, but not `std::sync`.
+  - `solaris` / `illumos`: maintained by @devnexen. Supports the entire test suite.
+  - `freebsd`: maintained by @YohDeadfall. Supports `std::env` and parts of `std::{thread, fs}`, but not `std::sync`.
   - `android`: **maintainer wanted**. Support very incomplete, but a basic "hello world" works.
   - `wasi`: **maintainer wanted**. Support very incomplete, not even standard output works, but an empty `main` function works.
 - For targets on other operating systems, Miri might fail before even reaching the `main` function.
diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh
index 0751f86da85..5583030b490 100755
--- a/src/tools/miri/ci/ci.sh
+++ b/src/tools/miri/ci/ci.sh
@@ -147,13 +147,14 @@ case $HOST_TARGET in
     # Extra tier 2
     TEST_TARGET=arm-unknown-linux-gnueabi run_tests
     TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture of choice
+    # Not officially supported tier 2
+    TEST_TARGET=x86_64-unknown-illumos run_tests
+    TEST_TARGET=x86_64-pc-solaris run_tests
     # Partially supported targets (tier 2)
     BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator
     UNIX="hello panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there
     TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe
     TEST_TARGET=i686-unknown-freebsd   run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe
-    TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe fs
-    TEST_TARGET=x86_64-pc-solaris      run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe fs
     TEST_TARGET=aarch64-linux-android  run_tests_minimal $BASIC $UNIX time hashmap random sync threadname pthread epoll eventfd
     TEST_TARGET=wasm32-wasip2          run_tests_minimal $BASIC wasm
     TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std
diff --git a/src/tools/miri/etc/rust_analyzer_vscode.json b/src/tools/miri/etc/rust_analyzer_vscode.json
index 5e51c3e8880..c646953e92b 100644
--- a/src/tools/miri/etc/rust_analyzer_vscode.json
+++ b/src/tools/miri/etc/rust_analyzer_vscode.json
@@ -5,21 +5,19 @@
         "cargo-miri/Cargo.toml",
         "miri-script/Cargo.toml",
     ],
-    "rust-analyzer.check.invocationLocation": "root",
     "rust-analyzer.check.invocationStrategy": "once",
     "rust-analyzer.check.overrideCommand": [
-        "env",
-        "MIRI_AUTO_OPS=no",
         "./miri",
         "clippy", // make this `check` when working with a locally built rustc
         "--message-format=json",
     ],
+    "rust-analyzer.cargo.extraEnv": {
+        "MIRI_AUTO_OPS": "no",
+        "MIRI_IN_RA": "1",
+    },
     // Contrary to what the name suggests, this also affects proc macros.
-    "rust-analyzer.cargo.buildScripts.invocationLocation": "root",
     "rust-analyzer.cargo.buildScripts.invocationStrategy": "once",
     "rust-analyzer.cargo.buildScripts.overrideCommand": [
-        "env",
-        "MIRI_AUTO_OPS=no",
         "./miri",
         "check",
         "--message-format=json",
diff --git a/src/tools/miri/miri b/src/tools/miri/miri
index ac1a7211c4e..b1b146d7990 100755
--- a/src/tools/miri/miri
+++ b/src/tools/miri/miri
@@ -3,12 +3,16 @@ set -e
 # We want to call the binary directly, so we need to know where it ends up.
 ROOT_DIR="$(dirname "$0")"
 MIRI_SCRIPT_TARGET_DIR="$ROOT_DIR"/miri-script/target
-# If stdout is not a terminal and we are not on CI, assume that we are being invoked by RA, and use JSON output.
-if ! [ -t 1 ] && [ -z "$CI" ]; then
+TOOLCHAIN="+nightly"
+# If we are being invoked for RA, use JSON output and the default toolchain (to make proc-macros
+# work in RA). This needs a different target dir to avoid mixing up the builds.
+if [ -n "$MIRI_IN_RA" ]; then
   MESSAGE_FORMAT="--message-format=json"
+  TOOLCHAIN=""
+  MIRI_SCRIPT_TARGET_DIR="$MIRI_SCRIPT_TARGET_DIR"/ra
 fi
 # We need a nightly toolchain, for `-Zroot-dir`.
-cargo +nightly build $CARGO_EXTRA_FLAGS --manifest-path "$ROOT_DIR"/miri-script/Cargo.toml \
+cargo $TOOLCHAIN build $CARGO_EXTRA_FLAGS --manifest-path "$ROOT_DIR"/miri-script/Cargo.toml \
   -Zroot-dir="$ROOT_DIR" \
   -q --target-dir "$MIRI_SCRIPT_TARGET_DIR" $MESSAGE_FORMAT || \
   ( echo "Failed to build miri-script. Is the 'nightly' toolchain installed?"; exit 1 )
diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs
index 75ac999e8be..17a7c06b525 100644
--- a/src/tools/miri/miri-script/src/commands.rs
+++ b/src/tools/miri/miri-script/src/commands.rs
@@ -423,7 +423,7 @@ impl Command {
                 .map(|path| path.into_os_string().into_string().unwrap())
                 .collect()
         } else {
-            benches.into_iter().map(Into::into).collect()
+            benches.into_iter().collect()
         };
         let target_flag = if let Some(target) = target {
             let mut flag = OsString::from("--target=");
@@ -564,6 +564,10 @@ impl Command {
         if bless {
             e.sh.set_var("RUSTC_BLESS", "Gesundheit");
         }
+        if e.sh.var("MIRI_TEST_TARGET").is_ok() {
+            // Avoid trouble due to an incorrectly set env var.
+            bail!("MIRI_TEST_TARGET must not be set when invoking `./miri test`");
+        }
         if let Some(target) = target {
             // Tell the harness which target to test.
             e.sh.set_var("MIRI_TEST_TARGET", target);
diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs
index a80fed8fcb6..279bdf8cc3f 100644
--- a/src/tools/miri/miri-script/src/main.rs
+++ b/src/tools/miri/miri-script/src/main.rs
@@ -111,6 +111,7 @@ pub enum Command {
     /// `rustup-toolchain-install-master` must be installed for this to work.
     Toolchain {
         /// Flags that are passed through to `rustup-toolchain-install-master`.
+        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
         flags: Vec<String>,
     },
     /// Pull and merge Miri changes from the rustc repo.
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 24bef6026d4..fa5dbb99e81 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-13170cd787cb733ed24842ee825bcbd98dc01476
+01706e1a34c87656fcbfce198608f4cd2ac6461a
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 9055aa30271..a2e9c63f79e 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -30,10 +30,10 @@ use std::ops::Range;
 use std::path::PathBuf;
 use std::str::FromStr;
 use std::sync::atomic::{AtomicI32, Ordering};
-use std::sync::{Arc, Once};
+use std::sync::Once;
 
 use miri::{
-    BacktraceStyle, BorrowTrackerMethod, MiriConfig, ProvenanceMode, RetagFields, ValidationMode,
+    BacktraceStyle, BorrowTrackerMethod, MiriConfig, MiriEntryFnType,ProvenanceMode, RetagFields, ValidationMode,
 };
 use rustc_abi::ExternAbi;
 use rustc_data_structures::sync;
@@ -51,7 +51,7 @@ use rustc_middle::query::LocalCrate;
 use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::util::Providers;
-use rustc_session::config::{CrateType, EntryFnType, ErrorOutputType, OptLevel};
+use rustc_session::config::{CrateType, ErrorOutputType, OptLevel};
 use rustc_session::search_paths::PathKind;
 use rustc_session::{CtfeBacktrace, EarlyDiagCtxt};
 use rustc_span::def_id::DefId;
@@ -73,9 +73,9 @@ impl MiriCompilerCalls {
     }
 }
 
-fn entry_fn(tcx: TyCtxt<'_>) -> (DefId, EntryFnType) {
-    if let Some(entry_def) = tcx.entry_fn(()) {
-        return entry_def;
+fn entry_fn(tcx: TyCtxt<'_>) -> (DefId, MiriEntryFnType) {
+    if let Some((def_id, entry_type)) = tcx.entry_fn(()) {
+        return (def_id, MiriEntryFnType::Rustc(entry_type));
     }
     // Look for a symbol in the local crate named `miri_start`, and treat that as the entry point.
     let sym = tcx.exported_symbols(LOCAL_CRATE).iter().find_map(|(sym, _)| {
@@ -102,7 +102,7 @@ fn entry_fn(tcx: TyCtxt<'_>) -> (DefId, EntryFnType) {
         .is_ok();
 
         if correct_func_sig {
-            (*id, EntryFnType::Start)
+            (*id, MiriEntryFnType::MiriStart)
         } else {
             tcx.dcx().fatal(
                 "`miri_start` must have the following signature:\n\
@@ -370,13 +370,10 @@ fn init_late_loggers(early_dcx: &EarlyDiagCtxt, tcx: TyCtxt<'_>) {
 fn run_compiler_and_exit(
     args: &[String],
     callbacks: &mut (dyn rustc_driver::Callbacks + Send),
-    using_internal_features: Arc<std::sync::atomic::AtomicBool>,
 ) -> ! {
     // Invoke compiler, and handle return code.
     let exit_code = rustc_driver::catch_with_exit_code(move || {
-        rustc_driver::RunCompiler::new(args, callbacks)
-            .set_using_internal_features(using_internal_features)
-            .run();
+        rustc_driver::run_compiler(args, callbacks);
         Ok(())
     });
     std::process::exit(exit_code)
@@ -467,8 +464,7 @@ fn main() {
     // If the environment asks us to actually be rustc, then do that.
     if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") {
         // Earliest rustc setup.
-        let using_internal_features =
-            rustc_driver::install_ice_hook(rustc_driver::DEFAULT_BUG_REPORT_URL, |_| ());
+        rustc_driver::install_ice_hook(rustc_driver::DEFAULT_BUG_REPORT_URL, |_| ());
         rustc_driver::init_rustc_env_logger(&early_dcx);
 
         let target_crate = if crate_kind == "target" {
@@ -492,16 +488,11 @@ fn main() {
         }
 
         // We cannot use `rustc_driver::main` as we want it to use `args` as the CLI arguments.
-        run_compiler_and_exit(
-            &args,
-            &mut MiriBeRustCompilerCalls { target_crate },
-            using_internal_features,
-        )
+        run_compiler_and_exit(&args, &mut MiriBeRustCompilerCalls { target_crate })
     }
 
     // Add an ICE bug report hook.
-    let using_internal_features =
-        rustc_driver::install_ice_hook("https://github.com/rust-lang/miri/issues/new", |_| ());
+    rustc_driver::install_ice_hook("https://github.com/rust-lang/miri/issues/new", |_| ());
 
     // Init loggers the Miri way.
     init_early_loggers(&early_dcx);
@@ -735,9 +726,5 @@ fn main() {
 
     debug!("rustc arguments: {:?}", rustc_args);
     debug!("crate arguments: {:?}", miri_config.args);
-    run_compiler_and_exit(
-        &rustc_args,
-        &mut MiriCompilerCalls::new(miri_config, many_seeds),
-        using_internal_features,
-    )
+    run_compiler_and_exit(&rustc_args, &mut MiriCompilerCalls::new(miri_config, many_seeds))
 }
diff --git a/src/tools/miri/src/concurrency/cpu_affinity.rs b/src/tools/miri/src/concurrency/cpu_affinity.rs
index 4e6bca93c5a..b47b614cf5f 100644
--- a/src/tools/miri/src/concurrency/cpu_affinity.rs
+++ b/src/tools/miri/src/concurrency/cpu_affinity.rs
@@ -54,8 +54,8 @@ impl CpuAffinityMask {
                 let chunk = self.0[start..].first_chunk_mut::<4>().unwrap();
                 let offset = cpu % 32;
                 *chunk = match target.options.endian {
-                    Endian::Little => (u32::from_le_bytes(*chunk) | 1 << offset).to_le_bytes(),
-                    Endian::Big => (u32::from_be_bytes(*chunk) | 1 << offset).to_be_bytes(),
+                    Endian::Little => (u32::from_le_bytes(*chunk) | (1 << offset)).to_le_bytes(),
+                    Endian::Big => (u32::from_be_bytes(*chunk) | (1 << offset)).to_be_bytes(),
                 };
             }
             8 => {
@@ -63,8 +63,8 @@ impl CpuAffinityMask {
                 let chunk = self.0[start..].first_chunk_mut::<8>().unwrap();
                 let offset = cpu % 64;
                 *chunk = match target.options.endian {
-                    Endian::Little => (u64::from_le_bytes(*chunk) | 1 << offset).to_le_bytes(),
-                    Endian::Big => (u64::from_be_bytes(*chunk) | 1 << offset).to_be_bytes(),
+                    Endian::Little => (u64::from_le_bytes(*chunk) | (1 << offset)).to_le_bytes(),
+                    Endian::Big => (u64::from_be_bytes(*chunk) | (1 << offset)).to_be_bytes(),
                 };
             }
             other => bug!("chunk size not supported: {other}"),
diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs
index ef4034cc0c1..14c72e9398a 100644
--- a/src/tools/miri/src/concurrency/sync.rs
+++ b/src/tools/miri/src/concurrency/sync.rs
@@ -422,7 +422,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     mutex_ref: MutexRef,
                     retval_dest: Option<(Scalar, MPlaceTy<'tcx>)>,
                 }
-                @unblock = |this| {
+                |this, unblock: UnblockKind| {
+                    assert_eq!(unblock, UnblockKind::Ready);
+
                     assert!(!this.mutex_is_locked(&mutex_ref));
                     this.mutex_lock(&mutex_ref);
 
@@ -538,7 +540,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     retval: Scalar,
                     dest: MPlaceTy<'tcx>,
                 }
-                @unblock = |this| {
+                |this, unblock: UnblockKind| {
+                    assert_eq!(unblock, UnblockKind::Ready);
                     this.rwlock_reader_lock(id);
                     this.write_scalar(retval, &dest)?;
                     interp_ok(())
@@ -623,7 +626,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     retval: Scalar,
                     dest: MPlaceTy<'tcx>,
                 }
-                @unblock = |this| {
+                |this, unblock: UnblockKind| {
+                    assert_eq!(unblock, UnblockKind::Ready);
                     this.rwlock_writer_lock(id);
                     this.write_scalar(retval, &dest)?;
                     interp_ok(())
@@ -677,25 +681,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     retval_timeout: Scalar,
                     dest: MPlaceTy<'tcx>,
                 }
-                @unblock = |this| {
-                    // The condvar was signaled. Make sure we get the clock for that.
-                    if let Some(data_race) = &this.machine.data_race {
-                        data_race.acquire_clock(
-                            &this.machine.sync.condvars[condvar].clock,
-                            &this.machine.threads,
-                        );
+                |this, unblock: UnblockKind| {
+                    match unblock {
+                        UnblockKind::Ready => {
+                            // The condvar was signaled. Make sure we get the clock for that.
+                            if let Some(data_race) = &this.machine.data_race {
+                                data_race.acquire_clock(
+                                    &this.machine.sync.condvars[condvar].clock,
+                                    &this.machine.threads,
+                                );
+                            }
+                            // Try to acquire the mutex.
+                            // The timeout only applies to the first wait (until the signal), not for mutex acquisition.
+                            this.condvar_reacquire_mutex(&mutex_ref, retval_succ, dest)
+                        }
+                        UnblockKind::TimedOut => {
+                            // We have to remove the waiter from the queue again.
+                            let thread = this.active_thread();
+                            let waiters = &mut this.machine.sync.condvars[condvar].waiters;
+                            waiters.retain(|waiter| *waiter != thread);
+                            // Now get back the lock.
+                            this.condvar_reacquire_mutex(&mutex_ref, retval_timeout, dest)
+                        }
                     }
-                    // Try to acquire the mutex.
-                    // The timeout only applies to the first wait (until the signal), not for mutex acquisition.
-                    this.condvar_reacquire_mutex(&mutex_ref, retval_succ, dest)
-                }
-                @timeout = |this| {
-                    // We have to remove the waiter from the queue again.
-                    let thread = this.active_thread();
-                    let waiters = &mut this.machine.sync.condvars[condvar].waiters;
-                    waiters.retain(|waiter| *waiter != thread);
-                    // Now get back the lock.
-                    this.condvar_reacquire_mutex(&mutex_ref, retval_timeout, dest)
                 }
             ),
         );
@@ -752,25 +760,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     dest: MPlaceTy<'tcx>,
                     errno_timeout: IoError,
                 }
-                @unblock = |this| {
-                    let futex = futex_ref.0.borrow();
-                    // Acquire the clock of the futex.
-                    if let Some(data_race) = &this.machine.data_race {
-                        data_race.acquire_clock(&futex.clock, &this.machine.threads);
+                |this, unblock: UnblockKind| {
+                    match unblock {
+                        UnblockKind::Ready => {
+                            let futex = futex_ref.0.borrow();
+                            // Acquire the clock of the futex.
+                            if let Some(data_race) = &this.machine.data_race {
+                                data_race.acquire_clock(&futex.clock, &this.machine.threads);
+                            }
+                            // Write the return value.
+                            this.write_scalar(retval_succ, &dest)?;
+                            interp_ok(())
+                        },
+                        UnblockKind::TimedOut => {
+                            // Remove the waiter from the futex.
+                            let thread = this.active_thread();
+                            let mut futex = futex_ref.0.borrow_mut();
+                            futex.waiters.retain(|waiter| waiter.thread != thread);
+                            // Set errno and write return value.
+                            this.set_last_error(errno_timeout)?;
+                            this.write_scalar(retval_timeout, &dest)?;
+                            interp_ok(())
+                        },
                     }
-                    // Write the return value.
-                    this.write_scalar(retval_succ, &dest)?;
-                    interp_ok(())
-                }
-                @timeout = |this| {
-                    // Remove the waiter from the futex.
-                    let thread = this.active_thread();
-                    let mut futex = futex_ref.0.borrow_mut();
-                    futex.waiters.retain(|waiter| waiter.thread != thread);
-                    // Set errno and write return value.
-                    this.set_last_error(errno_timeout)?;
-                    this.write_scalar(retval_timeout, &dest)?;
-                    interp_ok(())
                 }
             ),
         );
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index 730c27d0160..6d22dd8d68d 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -19,7 +19,7 @@ use crate::concurrency::data_race;
 use crate::shims::tls;
 use crate::*;
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[derive(Clone, Copy, Debug, PartialEq)]
 enum SchedulingAction {
     /// Execute step on the active thread.
     ExecuteStep,
@@ -30,6 +30,7 @@ enum SchedulingAction {
 }
 
 /// What to do with TLS allocations from terminated threads
+#[derive(Clone, Copy, Debug, PartialEq)]
 pub enum TlsAllocAction {
     /// Deallocate backing memory of thread-local statics as usual
     Deallocate,
@@ -38,71 +39,18 @@ pub enum TlsAllocAction {
     Leak,
 }
 
-/// Trait for callbacks that are executed when a thread gets unblocked.
-pub trait UnblockCallback<'tcx>: VisitProvenance {
-    /// Will be invoked when the thread was unblocked the "regular" way,
-    /// i.e. whatever event it was blocking on has happened.
-    fn unblock(self: Box<Self>, ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>) -> InterpResult<'tcx>;
-
-    /// Will be invoked when the timeout ellapsed without the event the
-    /// thread was blocking on having occurred.
-    fn timeout(self: Box<Self>, _ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>)
-    -> InterpResult<'tcx>;
+/// The argument type for the "unblock" callback, indicating why the thread got unblocked.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum UnblockKind {
+    /// Operation completed successfully, thread continues normal execution.
+    Ready,
+    /// The operation did not complete within its specified duration.
+    TimedOut,
 }
-pub type DynUnblockCallback<'tcx> = Box<dyn UnblockCallback<'tcx> + 'tcx>;
-
-#[macro_export]
-macro_rules! callback {
-    (
-        @capture<$tcx:lifetime $(,)? $($lft:lifetime),*> { $($name:ident: $type:ty),* $(,)? }
-        @unblock = |$this:ident| $unblock:block
-    ) => {
-        callback!(
-            @capture<$tcx, $($lft),*> { $($name: $type),* }
-            @unblock = |$this| $unblock
-            @timeout = |_this| {
-                unreachable!(
-                    "timeout on a thread that was blocked without a timeout (or someone forgot to overwrite this method)"
-                )
-            }
-        )
-    };
-    (
-        @capture<$tcx:lifetime $(,)? $($lft:lifetime),*> { $($name:ident: $type:ty),* $(,)? }
-        @unblock = |$this:ident| $unblock:block
-        @timeout = |$this_timeout:ident| $timeout:block
-    ) => {{
-        struct Callback<$tcx, $($lft),*> {
-            $($name: $type,)*
-            _phantom: std::marker::PhantomData<&$tcx ()>,
-        }
-
-        impl<$tcx, $($lft),*> VisitProvenance for Callback<$tcx, $($lft),*> {
-            #[allow(unused_variables)]
-            fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
-                $(
-                    self.$name.visit_provenance(visit);
-                )*
-            }
-        }
-
-        impl<$tcx, $($lft),*> UnblockCallback<$tcx> for Callback<$tcx, $($lft),*> {
-            fn unblock(self: Box<Self>, $this: &mut MiriInterpCx<$tcx>) -> InterpResult<$tcx> {
-                #[allow(unused_variables)]
-                let Callback { $($name,)* _phantom } = *self;
-                $unblock
-            }
 
-            fn timeout(self: Box<Self>, $this_timeout: &mut MiriInterpCx<$tcx>) -> InterpResult<$tcx> {
-                #[allow(unused_variables)]
-                let Callback { $($name,)* _phantom } = *self;
-                $timeout
-            }
-        }
-
-        Box::new(Callback { $($name,)* _phantom: std::marker::PhantomData })
-    }}
-}
+/// Type alias for unblock callbacks, i.e. machine callbacks invoked when
+/// a thread gets unblocked.
+pub type DynUnblockCallback<'tcx> = DynMachineCallback<'tcx, UnblockKind>;
 
 /// A thread identifier.
 #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
@@ -656,7 +604,8 @@ impl<'tcx> ThreadManager<'tcx> {
                     @capture<'tcx> {
                         joined_thread_id: ThreadId,
                     }
-                    @unblock = |this| {
+                    |this, unblock: UnblockKind| {
+                        assert_eq!(unblock, UnblockKind::Ready);
                         if let Some(data_race) = &mut this.machine.data_race {
                             data_race.thread_joined(&this.machine.threads, joined_thread_id);
                         }
@@ -842,7 +791,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
             // 2. Make the scheduler the only place that can change the active
             //    thread.
             let old_thread = this.machine.threads.set_active_thread_id(thread);
-            callback.timeout(this)?;
+            callback.call(this, UnblockKind::TimedOut)?;
             this.machine.threads.set_active_thread_id(old_thread);
         }
         // found_callback can remain None if the computer's clock
@@ -1084,7 +1033,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         };
         // The callback must be executed in the previously blocked thread.
         let old_thread = this.machine.threads.set_active_thread_id(thread);
-        callback.unblock(this)?;
+        callback.call(this, UnblockKind::Ready)?;
         this.machine.threads.set_active_thread_id(old_thread);
         interp_ok(())
     }
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index eaf4b30c660..c8f04e25207 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -19,6 +19,12 @@ use crate::diagnostics::report_leaks;
 use crate::shims::tls;
 use crate::*;
 
+#[derive(Copy, Clone, Debug)]
+pub enum MiriEntryFnType {
+    MiriStart,
+    Rustc(EntryFnType),
+}
+
 /// When the main thread would exit, we will yield to any other thread that is ready to execute.
 /// But we must only do that a finite number of times, or a background thread running `loop {}`
 /// will hang the program.
@@ -272,7 +278,7 @@ impl<'tcx> MainThreadState<'tcx> {
 pub fn create_ecx<'tcx>(
     tcx: TyCtxt<'tcx>,
     entry_id: DefId,
-    entry_type: EntryFnType,
+    entry_type: MiriEntryFnType,
     config: &MiriConfig,
 ) -> InterpResult<'tcx, InterpCx<'tcx, MiriMachine<'tcx>>> {
     let typing_env = ty::TypingEnv::fully_monomorphized();
@@ -300,7 +306,7 @@ pub fn create_ecx<'tcx>(
     // Setup first stack frame.
     let entry_instance = ty::Instance::mono(tcx, entry_id);
 
-    // First argument is constructed later, because it's skipped if the entry function uses #[start].
+    // First argument is constructed later, because it's skipped for `miri_start.`
 
     // Second argument (argc): length of `config.args`.
     let argc =
@@ -373,11 +379,9 @@ pub fn create_ecx<'tcx>(
     // Call start function.
 
     match entry_type {
-        EntryFnType::Main { .. } => {
+        MiriEntryFnType::Rustc(EntryFnType::Main { .. }) => {
             let start_id = tcx.lang_items().start_fn().unwrap_or_else(|| {
-                tcx.dcx().fatal(
-                    "could not find start function. Make sure the entry point is marked with `#[start]`."
-                );
+                tcx.dcx().fatal("could not find start lang item");
             });
             let main_ret_ty = tcx.fn_sig(entry_id).no_bound_vars().unwrap().output();
             let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
@@ -413,7 +417,7 @@ pub fn create_ecx<'tcx>(
                 StackPopCleanup::Root { cleanup: true },
             )?;
         }
-        EntryFnType::Start => {
+        MiriEntryFnType::MiriStart => {
             ecx.call_function(
                 entry_instance,
                 ExternAbi::Rust,
@@ -434,7 +438,7 @@ pub fn create_ecx<'tcx>(
 pub fn eval_entry<'tcx>(
     tcx: TyCtxt<'tcx>,
     entry_id: DefId,
-    entry_type: EntryFnType,
+    entry_type: MiriEntryFnType,
     config: MiriConfig,
 ) -> Option<i32> {
     // Copy setting before we move `config`.
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index adfec33beac..ca8dbdac125 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -262,6 +262,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         })
     }
 
+    /// Helper function to get a `libc` constant as an `u64`.
+    fn eval_libc_u64(&self, name: &str) -> u64 {
+        // TODO: Cache the result.
+        self.eval_libc(name).to_u64().unwrap_or_else(|_err| {
+            panic!("required libc item has unexpected type (not `u64`): {name}")
+        })
+    }
+
     /// Helper function to get a `windows` constant as a `Scalar`.
     fn eval_windows(&self, module: &str, name: &str) -> Scalar {
         self.eval_context_ref().eval_path_scalar(&["std", "sys", "pal", "windows", module, name])
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index e02d51afcef..2955dc38a8c 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -13,6 +13,8 @@
 #![feature(strict_overflow_ops)]
 #![feature(pointer_is_aligned_to)]
 #![feature(unqualified_local_imports)]
+#![feature(derive_coerce_pointee)]
+#![feature(arbitrary_self_types)]
 // Configure clippy and other lints
 #![allow(
     clippy::collapsible_else_if,
@@ -126,21 +128,21 @@ pub use crate::concurrency::sync::{
     CondvarId, EvalContextExt as _, MutexRef, RwLockId, SynchronizationObjects,
 };
 pub use crate::concurrency::thread::{
-    BlockReason, EvalContextExt as _, StackEmptyCallback, ThreadId, ThreadManager, TimeoutAnchor,
-    TimeoutClock, UnblockCallback,
+    BlockReason, DynUnblockCallback, EvalContextExt as _, StackEmptyCallback, ThreadId,
+    ThreadManager, TimeoutAnchor, TimeoutClock, UnblockKind,
 };
 pub use crate::diagnostics::{
     EvalContextExt as _, NonHaltingDiagnostic, TerminationInfo, report_error,
 };
 pub use crate::eval::{
-    AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, RejectOpWith, ValidationMode,
-    create_ecx, eval_entry,
+    AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, MiriEntryFnType, RejectOpWith,
+    ValidationMode, create_ecx, eval_entry,
 };
 pub use crate::helpers::{AccessKind, EvalContextExt as _};
 pub use crate::intrinsics::EvalContextExt as _;
 pub use crate::machine::{
-    AllocExtra, FrameExtra, MemoryKind, MiriInterpCx, MiriInterpCxExt, MiriMachine, MiriMemoryKind,
-    PrimitiveLayouts, Provenance, ProvenanceExtra,
+    AllocExtra, DynMachineCallback, FrameExtra, MachineCallback, MemoryKind, MiriInterpCx,
+    MiriInterpCxExt, MiriMachine, MiriMemoryKind, PrimitiveLayouts, Provenance, ProvenanceExtra,
 };
 pub use crate::mono_hash_map::MonoHashMap;
 pub use crate::operator::EvalContextExt as _;
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 5e8f616a37e..845ba484326 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -1723,3 +1723,69 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         Cow::Borrowed(ecx.machine.union_data_ranges.entry(ty).or_insert_with(compute_range))
     }
 }
+
+/// Trait for callbacks handling asynchronous machine operations.
+pub trait MachineCallback<'tcx, T>: VisitProvenance {
+    /// The function to be invoked when the callback is fired.
+    fn call(
+        self: Box<Self>,
+        ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>,
+        arg: T,
+    ) -> InterpResult<'tcx>;
+}
+
+/// Type alias for boxed machine callbacks with generic argument type.
+pub type DynMachineCallback<'tcx, T> = Box<dyn MachineCallback<'tcx, T> + 'tcx>;
+
+/// Creates a `DynMachineCallback`:
+///
+/// ```rust
+/// callback!(
+///     @capture<'tcx> {
+///         var1: Ty1,
+///         var2: Ty2<'tcx>,
+///     }
+///     |this, arg: ArgTy| {
+///         // Implement the callback here.
+///         todo!()
+///     }
+/// )
+/// ```
+///
+/// All the argument types must implement `VisitProvenance`.
+#[macro_export]
+macro_rules! callback {
+    (@capture<$tcx:lifetime $(,)? $($lft:lifetime),*>
+        { $($name:ident: $type:ty),* $(,)? }
+     |$this:ident, $arg:ident: $arg_ty:ty| $body:expr $(,)?) => {{
+        struct Callback<$tcx, $($lft),*> {
+            $($name: $type,)*
+            _phantom: std::marker::PhantomData<&$tcx ()>,
+        }
+
+        impl<$tcx, $($lft),*> VisitProvenance for Callback<$tcx, $($lft),*> {
+            fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
+                $(
+                    self.$name.visit_provenance(_visit);
+                )*
+            }
+        }
+
+        impl<$tcx, $($lft),*> MachineCallback<$tcx, $arg_ty> for Callback<$tcx, $($lft),*> {
+            fn call(
+                self: Box<Self>,
+                $this: &mut MiriInterpCx<$tcx>,
+                $arg: $arg_ty
+            ) -> InterpResult<$tcx> {
+                #[allow(unused_variables)]
+                let Callback { $($name,)* _phantom } = *self;
+                $body
+            }
+        }
+
+        Box::new(Callback {
+            $($name,)*
+            _phantom: std::marker::PhantomData
+        })
+    }};
+}
diff --git a/src/tools/miri/src/shims/files.rs b/src/tools/miri/src/shims/files.rs
index f673b834be2..73425eee515 100644
--- a/src/tools/miri/src/shims/files.rs
+++ b/src/tools/miri/src/shims/files.rs
@@ -1,6 +1,7 @@
 use std::any::Any;
 use std::collections::BTreeMap;
 use std::io::{IsTerminal, Read, SeekFrom, Write};
+use std::marker::CoercePointee;
 use std::ops::Deref;
 use std::rc::{Rc, Weak};
 use std::{fs, io};
@@ -10,16 +11,132 @@ use rustc_abi::Size;
 use crate::shims::unix::UnixFileDescription;
 use crate::*;
 
+/// A unique id for file descriptions. While we could use the address, considering that
+/// is definitely unique, the address would expose interpreter internal state when used
+/// for sorting things. So instead we generate a unique id per file description is the name
+/// for all `dup`licates and is never reused.
+#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
+pub struct FdId(usize);
+
+#[derive(Debug, Clone)]
+struct FdIdWith<T: ?Sized> {
+    id: FdId,
+    inner: T,
+}
+
+/// A refcounted pointer to a file description, also tracking the
+/// globally unique ID of this file description.
+#[repr(transparent)]
+#[derive(CoercePointee, Debug)]
+pub struct FileDescriptionRef<T: ?Sized>(Rc<FdIdWith<T>>);
+
+impl<T: ?Sized> Clone for FileDescriptionRef<T> {
+    fn clone(&self) -> Self {
+        FileDescriptionRef(self.0.clone())
+    }
+}
+
+impl<T: ?Sized> Deref for FileDescriptionRef<T> {
+    type Target = T;
+    fn deref(&self) -> &T {
+        &self.0.inner
+    }
+}
+
+impl<T: ?Sized> FileDescriptionRef<T> {
+    pub fn id(&self) -> FdId {
+        self.0.id
+    }
+}
+
+/// Holds a weak reference to the actual file description.
+#[derive(Debug)]
+pub struct WeakFileDescriptionRef<T: ?Sized>(Weak<FdIdWith<T>>);
+
+impl<T: ?Sized> Clone for WeakFileDescriptionRef<T> {
+    fn clone(&self) -> Self {
+        WeakFileDescriptionRef(self.0.clone())
+    }
+}
+
+impl<T: ?Sized> FileDescriptionRef<T> {
+    pub fn downgrade(this: &Self) -> WeakFileDescriptionRef<T> {
+        WeakFileDescriptionRef(Rc::downgrade(&this.0))
+    }
+}
+
+impl<T: ?Sized> WeakFileDescriptionRef<T> {
+    pub fn upgrade(&self) -> Option<FileDescriptionRef<T>> {
+        self.0.upgrade().map(FileDescriptionRef)
+    }
+}
+
+impl<T> VisitProvenance for WeakFileDescriptionRef<T> {
+    fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
+        // A weak reference can never be the only reference to some pointer or place.
+        // Since the actual file description is tracked by strong ref somewhere,
+        // it is ok to make this a NOP operation.
+    }
+}
+
+/// A helper trait to indirectly allow downcasting on `Rc<FdIdWith<dyn _>>`.
+/// Ideally we'd just add a `FdIdWith<Self>: Any` bound to the `FileDescription` trait,
+/// but that does not allow upcasting.
+pub trait FileDescriptionExt: 'static {
+    fn into_rc_any(self: FileDescriptionRef<Self>) -> Rc<dyn Any>;
+
+    /// We wrap the regular `close` function generically, so both handle `Rc::into_inner`
+    /// and epoll interest management.
+    fn close_ref<'tcx>(
+        self: FileDescriptionRef<Self>,
+        communicate_allowed: bool,
+        ecx: &mut MiriInterpCx<'tcx>,
+    ) -> InterpResult<'tcx, io::Result<()>>;
+}
+
+impl<T: FileDescription + 'static> FileDescriptionExt for T {
+    fn into_rc_any(self: FileDescriptionRef<Self>) -> Rc<dyn Any> {
+        self.0
+    }
+
+    fn close_ref<'tcx>(
+        self: FileDescriptionRef<Self>,
+        communicate_allowed: bool,
+        ecx: &mut MiriInterpCx<'tcx>,
+    ) -> InterpResult<'tcx, io::Result<()>> {
+        match Rc::into_inner(self.0) {
+            Some(fd) => {
+                // Remove entry from the global epoll_event_interest table.
+                ecx.machine.epoll_interests.remove(fd.id);
+
+                fd.inner.close(communicate_allowed, ecx)
+            }
+            None => {
+                // Not the last reference.
+                interp_ok(Ok(()))
+            }
+        }
+    }
+}
+
+pub type DynFileDescriptionRef = FileDescriptionRef<dyn FileDescription>;
+
+impl FileDescriptionRef<dyn FileDescription> {
+    pub fn downcast<T: FileDescription + 'static>(self) -> Option<FileDescriptionRef<T>> {
+        let inner = self.into_rc_any().downcast::<FdIdWith<T>>().ok()?;
+        Some(FileDescriptionRef(inner))
+    }
+}
+
 /// Represents an open file description.
-pub trait FileDescription: std::fmt::Debug + Any {
+pub trait FileDescription: std::fmt::Debug + FileDescriptionExt {
     fn name(&self) -> &'static str;
 
     /// Reads as much as possible into the given buffer `ptr`.
     /// `len` indicates how many bytes we should try to read.
     /// `dest` is where the return value should be stored: number of bytes read, or `-1` in case of error.
     fn read<'tcx>(
-        &self,
-        _self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         _communicate_allowed: bool,
         _ptr: Pointer,
         _len: usize,
@@ -33,8 +150,7 @@ pub trait FileDescription: std::fmt::Debug + Any {
     /// `len` indicates how many bytes we should try to write.
     /// `dest` is where the return value should be stored: number of bytes written, or `-1` in case of error.
     fn write<'tcx>(
-        &self,
-        _self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         _communicate_allowed: bool,
         _ptr: Pointer,
         _len: usize,
@@ -54,11 +170,15 @@ pub trait FileDescription: std::fmt::Debug + Any {
         throw_unsup_format!("cannot seek on {}", self.name());
     }
 
+    /// Close the file descriptor.
     fn close<'tcx>(
-        self: Box<Self>,
+        self,
         _communicate_allowed: bool,
         _ecx: &mut MiriInterpCx<'tcx>,
-    ) -> InterpResult<'tcx, io::Result<()>> {
+    ) -> InterpResult<'tcx, io::Result<()>>
+    where
+        Self: Sized,
+    {
         throw_unsup_format!("cannot close {}", self.name());
     }
 
@@ -77,21 +197,13 @@ pub trait FileDescription: std::fmt::Debug + Any {
     }
 }
 
-impl dyn FileDescription {
-    #[inline(always)]
-    pub fn downcast<T: Any>(&self) -> Option<&T> {
-        (self as &dyn Any).downcast_ref()
-    }
-}
-
 impl FileDescription for io::Stdin {
     fn name(&self) -> &'static str {
         "stdin"
     }
 
     fn read<'tcx>(
-        &self,
-        _self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
@@ -103,7 +215,7 @@ impl FileDescription for io::Stdin {
             // We want isolation mode to be deterministic, so we have to disallow all reads, even stdin.
             helpers::isolation_abort_error("`read` from stdin")?;
         }
-        let result = Read::read(&mut { self }, &mut bytes);
+        let result = Read::read(&mut &*self, &mut bytes);
         match result {
             Ok(read_size) => ecx.return_read_success(ptr, &bytes, read_size, dest),
             Err(e) => ecx.set_last_error_and_return(e, dest),
@@ -121,8 +233,7 @@ impl FileDescription for io::Stdout {
     }
 
     fn write<'tcx>(
-        &self,
-        _self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         _communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
@@ -131,7 +242,7 @@ impl FileDescription for io::Stdout {
     ) -> InterpResult<'tcx> {
         let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?;
         // We allow writing to stderr even with isolation enabled.
-        let result = Write::write(&mut { self }, bytes);
+        let result = Write::write(&mut &*self, bytes);
         // Stdout is buffered, flush to make sure it appears on the
         // screen.  This is the write() syscall of the interpreted
         // program, we want it to correspond to a write() syscall on
@@ -155,8 +266,7 @@ impl FileDescription for io::Stderr {
     }
 
     fn write<'tcx>(
-        &self,
-        _self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         _communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
@@ -166,7 +276,7 @@ impl FileDescription for io::Stderr {
         let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?;
         // We allow writing to stderr even with isolation enabled.
         // No need to flush, stderr is not buffered.
-        let result = Write::write(&mut { self }, bytes);
+        let result = Write::write(&mut &*self, bytes);
         match result {
             Ok(write_size) => ecx.return_write_success(write_size, dest),
             Err(e) => ecx.set_last_error_and_return(e, dest),
@@ -188,8 +298,7 @@ impl FileDescription for NullOutput {
     }
 
     fn write<'tcx>(
-        &self,
-        _self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         _communicate_allowed: bool,
         _ptr: Pointer,
         len: usize,
@@ -201,91 +310,10 @@ impl FileDescription for NullOutput {
     }
 }
 
-/// Structure contains both the file description and its unique identifier.
-#[derive(Clone, Debug)]
-pub struct FileDescWithId<T: FileDescription + ?Sized> {
-    id: FdId,
-    file_description: Box<T>,
-}
-
-#[derive(Clone, Debug)]
-pub struct FileDescriptionRef(Rc<FileDescWithId<dyn FileDescription>>);
-
-impl Deref for FileDescriptionRef {
-    type Target = dyn FileDescription;
-
-    fn deref(&self) -> &Self::Target {
-        &*self.0.file_description
-    }
-}
-
-impl FileDescriptionRef {
-    fn new(fd: impl FileDescription, id: FdId) -> Self {
-        FileDescriptionRef(Rc::new(FileDescWithId { id, file_description: Box::new(fd) }))
-    }
-
-    pub fn close<'tcx>(
-        self,
-        communicate_allowed: bool,
-        ecx: &mut MiriInterpCx<'tcx>,
-    ) -> InterpResult<'tcx, io::Result<()>> {
-        // Destroy this `Rc` using `into_inner` so we can call `close` instead of
-        // implicitly running the destructor of the file description.
-        let id = self.get_id();
-        match Rc::into_inner(self.0) {
-            Some(fd) => {
-                // Remove entry from the global epoll_event_interest table.
-                ecx.machine.epoll_interests.remove(id);
-
-                fd.file_description.close(communicate_allowed, ecx)
-            }
-            None => interp_ok(Ok(())),
-        }
-    }
-
-    pub fn downgrade(&self) -> WeakFileDescriptionRef {
-        WeakFileDescriptionRef { weak_ref: Rc::downgrade(&self.0) }
-    }
-
-    pub fn get_id(&self) -> FdId {
-        self.0.id
-    }
-}
-
-/// Holds a weak reference to the actual file description.
-#[derive(Clone, Debug, Default)]
-pub struct WeakFileDescriptionRef {
-    weak_ref: Weak<FileDescWithId<dyn FileDescription>>,
-}
-
-impl WeakFileDescriptionRef {
-    pub fn upgrade(&self) -> Option<FileDescriptionRef> {
-        if let Some(file_desc_with_id) = self.weak_ref.upgrade() {
-            return Some(FileDescriptionRef(file_desc_with_id));
-        }
-        None
-    }
-}
-
-impl VisitProvenance for WeakFileDescriptionRef {
-    fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
-        // A weak reference can never be the only reference to some pointer or place.
-        // Since the actual file description is tracked by strong ref somewhere,
-        // it is ok to make this a NOP operation.
-    }
-}
-
-/// A unique id for file descriptions. While we could use the address, considering that
-/// is definitely unique, the address would expose interpreter internal state when used
-/// for sorting things. So instead we generate a unique id per file description is the name
-/// for all `dup`licates and is never reused.
-#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
-pub struct FdId(usize);
-
 /// The file descriptor table
 #[derive(Debug)]
 pub struct FdTable {
-    pub fds: BTreeMap<i32, FileDescriptionRef>,
+    pub fds: BTreeMap<i32, DynFileDescriptionRef>,
     /// Unique identifier for file description, used to differentiate between various file description.
     next_file_description_id: FdId,
 }
@@ -313,8 +341,9 @@ impl FdTable {
         fds
     }
 
-    pub fn new_ref(&mut self, fd: impl FileDescription) -> FileDescriptionRef {
-        let file_handle = FileDescriptionRef::new(fd, self.next_file_description_id);
+    pub fn new_ref<T: FileDescription>(&mut self, fd: T) -> FileDescriptionRef<T> {
+        let file_handle =
+            FileDescriptionRef(Rc::new(FdIdWith { id: self.next_file_description_id, inner: fd }));
         self.next_file_description_id = FdId(self.next_file_description_id.0.strict_add(1));
         file_handle
     }
@@ -325,12 +354,16 @@ impl FdTable {
         self.insert(fd_ref)
     }
 
-    pub fn insert(&mut self, fd_ref: FileDescriptionRef) -> i32 {
+    pub fn insert(&mut self, fd_ref: DynFileDescriptionRef) -> i32 {
         self.insert_with_min_num(fd_ref, 0)
     }
 
     /// Insert a file description, giving it a file descriptor that is at least `min_fd_num`.
-    pub fn insert_with_min_num(&mut self, file_handle: FileDescriptionRef, min_fd_num: i32) -> i32 {
+    pub fn insert_with_min_num(
+        &mut self,
+        file_handle: DynFileDescriptionRef,
+        min_fd_num: i32,
+    ) -> i32 {
         // Find the lowest unused FD, starting from min_fd. If the first such unused FD is in
         // between used FDs, the find_map combinator will return it. If the first such unused FD
         // is after all other used FDs, the find_map combinator will return None, and we will use
@@ -356,12 +389,12 @@ impl FdTable {
         new_fd_num
     }
 
-    pub fn get(&self, fd_num: i32) -> Option<FileDescriptionRef> {
+    pub fn get(&self, fd_num: i32) -> Option<DynFileDescriptionRef> {
         let fd = self.fds.get(&fd_num)?;
         Some(fd.clone())
     }
 
-    pub fn remove(&mut self, fd_num: i32) -> Option<FileDescriptionRef> {
+    pub fn remove(&mut self, fd_num: i32) -> Option<DynFileDescriptionRef> {
         self.fds.remove(&fd_num)
     }
 
diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs
index 87be5a521d1..8c9e1860f31 100644
--- a/src/tools/miri/src/shims/native_lib.rs
+++ b/src/tools/miri/src/shims/native_lib.rs
@@ -72,7 +72,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             // Functions with no declared return type (i.e., the default return)
             // have the output_type `Tuple([])`.
-            ty::Tuple(t_list) if t_list.len() == 0 => {
+            ty::Tuple(t_list) if t_list.is_empty() => {
                 unsafe { ffi::call::<()>(ptr, libffi_args.as_slice()) };
                 return interp_ok(ImmTy::uninit(dest.layout));
             }
diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs
index 72d98bc1c48..d6c77d9c4d9 100644
--- a/src/tools/miri/src/shims/time.rs
+++ b/src/tools/miri/src/shims/time.rs
@@ -331,8 +331,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             Some((TimeoutClock::Monotonic, TimeoutAnchor::Relative, duration)),
             callback!(
                 @capture<'tcx> {}
-                @unblock = |_this| { panic!("sleeping thread unblocked before time is up") }
-                @timeout = |_this| { interp_ok(()) }
+                |_this, unblock: UnblockKind| {
+                    assert_eq!(unblock, UnblockKind::TimedOut);
+                    interp_ok(())
+                }
             ),
         );
         interp_ok(Scalar::from_i32(0))
@@ -353,8 +355,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             Some((TimeoutClock::Monotonic, TimeoutAnchor::Relative, duration)),
             callback!(
                 @capture<'tcx> {}
-                @unblock = |_this| { panic!("sleeping thread unblocked before time is up") }
-                @timeout = |_this| { interp_ok(()) }
+                |_this, unblock: UnblockKind| {
+                    assert_eq!(unblock, UnblockKind::TimedOut);
+                    interp_ok(())
+                }
             ),
         );
         interp_ok(())
diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs
index e5dead1a263..0b59490308b 100644
--- a/src/tools/miri/src/shims/unix/fd.rs
+++ b/src/tools/miri/src/shims/unix/fd.rs
@@ -88,7 +88,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // If old_fd and new_fd point to the same description, then `dup_fd` ensures we keep the underlying file description alive.
             if let Some(old_new_fd) = this.machine.fds.fds.insert(new_fd_num, fd) {
                 // Ignore close error (not interpreter's) according to dup2() doc.
-                old_new_fd.close(this.machine.communicate(), this)?.ok();
+                old_new_fd.close_ref(this.machine.communicate(), this)?.ok();
             }
         }
         interp_ok(Scalar::from_i32(new_fd_num))
@@ -122,7 +122,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         };
 
         let result = fd.as_unix().flock(this.machine.communicate(), parsed_op)?;
-        drop(fd);
         // return `0` if flock is successful
         let result = result.map(|()| 0i32);
         interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
@@ -198,7 +197,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let Some(fd) = this.machine.fds.remove(fd_num) else {
             return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
-        let result = fd.close(this.machine.communicate(), this)?;
+        let result = fd.close_ref(this.machine.communicate(), this)?;
         // return `0` if close is successful
         let result = result.map(|()| 0i32);
         interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
@@ -246,7 +245,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // `usize::MAX` because it is bounded by the host's `isize`.
 
         match offset {
-            None => fd.read(&fd, communicate, buf, count, dest, this)?,
+            None => fd.read(communicate, buf, count, dest, this)?,
             Some(offset) => {
                 let Ok(offset) = u64::try_from(offset) else {
                     return this.set_last_error_and_return(LibcError("EINVAL"), dest);
@@ -286,7 +285,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         };
 
         match offset {
-            None => fd.write(&fd, communicate, buf, count, dest, this)?,
+            None => fd.write(communicate, buf, count, dest, this)?,
             Some(offset) => {
                 let Ok(offset) = u64::try_from(offset) else {
                     return this.set_last_error_and_return(LibcError("EINVAL"), dest);
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index f47a96b10fe..3353cf2cc59 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -109,56 +109,54 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern.
-        #[rustfmt::skip]
         match link_name.as_str() {
             // Environment related shims
             "getenv" => {
-                let [name] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [name] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.getenv(name)?;
                 this.write_pointer(result, dest)?;
             }
             "unsetenv" => {
-                let [name] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [name] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.unsetenv(name)?;
                 this.write_scalar(result, dest)?;
             }
             "setenv" => {
-                let [name, value, overwrite] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [name, value, overwrite] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.read_scalar(overwrite)?.to_i32()?;
                 let result = this.setenv(name, value)?;
                 this.write_scalar(result, dest)?;
             }
             "getcwd" => {
-                let [buf, size] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [buf, size] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.getcwd(buf, size)?;
                 this.write_pointer(result, dest)?;
             }
             "chdir" => {
-                let [path] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [path] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.chdir(path)?;
                 this.write_scalar(result, dest)?;
             }
             "getpid" => {
-                let [] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.getpid()?;
                 this.write_scalar(result, dest)?;
             }
             "sysconf" => {
-                let [val] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                let [val] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.sysconf(val)?;
                 this.write_scalar(result, dest)?;
             }
             // File descriptors
             "read" => {
-                let [fd, buf, count] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, buf, count] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let buf = this.read_pointer(buf)?;
                 let count = this.read_target_usize(count)?;
                 this.read(fd, buf, count, None, dest)?;
             }
             "write" => {
-                let [fd, buf, n] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, buf, n] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let buf = this.read_pointer(buf)?;
                 let count = this.read_target_usize(n)?;
@@ -166,7 +164,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write(fd, buf, count, None, dest)?;
             }
             "pread" => {
-                let [fd, buf, count, offset] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, buf, count, offset] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let buf = this.read_pointer(buf)?;
                 let count = this.read_target_usize(count)?;
@@ -174,7 +172,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.read(fd, buf, count, Some(offset), dest)?;
             }
             "pwrite" => {
-                let [fd, buf, n, offset] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, buf, n, offset] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let buf = this.read_pointer(buf)?;
                 let count = this.read_target_usize(n)?;
@@ -183,49 +181,51 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write(fd, buf, count, Some(offset), dest)?;
             }
             "pread64" => {
-                let [fd, buf, count, offset] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, buf, count, offset] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let buf = this.read_pointer(buf)?;
                 let count = this.read_target_usize(count)?;
-                let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?;
+                let offset =
+                    this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?;
                 this.read(fd, buf, count, Some(offset), dest)?;
             }
             "pwrite64" => {
-                let [fd, buf, n, offset] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, buf, n, offset] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let buf = this.read_pointer(buf)?;
                 let count = this.read_target_usize(n)?;
-                let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?;
+                let offset =
+                    this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?;
                 trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
                 this.write(fd, buf, count, Some(offset), dest)?;
             }
             "close" => {
-                let [fd] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.close(fd)?;
                 this.write_scalar(result, dest)?;
             }
             "fcntl" => {
                 // `fcntl` is variadic. The argument count is checked based on the first argument
                 // in `this.fcntl()`, so we do not use `check_shim` here.
-                this.check_abi_and_shim_symbol_clash(abi, Conv::C , link_name)?;
+                this.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?;
                 let result = this.fcntl(args)?;
                 this.write_scalar(result, dest)?;
             }
             "dup" => {
-                let [old_fd] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [old_fd] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
                 let new_fd = this.dup(old_fd)?;
                 this.write_scalar(new_fd, dest)?;
             }
             "dup2" => {
-                let [old_fd, new_fd] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [old_fd, new_fd] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
                 let new_fd = this.read_scalar(new_fd)?.to_i32()?;
                 let result = this.dup2(old_fd, new_fd)?;
                 this.write_scalar(result, dest)?;
             }
             "flock" => {
-                let [fd, op] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, op] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let op = this.read_scalar(op)?.to_i32()?;
                 let result = this.flock(fd, op)?;
@@ -234,48 +234,49 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // File and file system access
             "open" | "open64" => {
-                // `open` is variadic, the third argument is only present when the second argument has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set
-                this.check_abi_and_shim_symbol_clash(abi, Conv::C , link_name)?;
+                // `open` is variadic, the third argument is only present when the second argument
+                // has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set
+                this.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?;
                 let result = this.open(args)?;
                 this.write_scalar(result, dest)?;
             }
             "unlink" => {
-                let [path] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [path] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.unlink(path)?;
                 this.write_scalar(result, dest)?;
             }
             "symlink" => {
-                let [target, linkpath] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [target, linkpath] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.symlink(target, linkpath)?;
                 this.write_scalar(result, dest)?;
             }
             "rename" => {
-                let [oldpath, newpath] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [oldpath, newpath] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.rename(oldpath, newpath)?;
                 this.write_scalar(result, dest)?;
             }
             "mkdir" => {
-                let [path, mode] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [path, mode] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.mkdir(path, mode)?;
                 this.write_scalar(result, dest)?;
             }
             "rmdir" => {
-                let [path] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [path] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.rmdir(path)?;
                 this.write_scalar(result, dest)?;
             }
             "opendir" => {
-                let [name] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [name] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.opendir(name)?;
                 this.write_scalar(result, dest)?;
             }
             "closedir" => {
-                let [dirp] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [dirp] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.closedir(dirp)?;
                 this.write_scalar(result, dest)?;
             }
             "lseek64" => {
-                let [fd, offset, whence] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, offset, whence] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let offset = this.read_scalar(offset)?.to_i64()?;
                 let whence = this.read_scalar(whence)?.to_i32()?;
@@ -283,7 +284,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(result, dest)?;
             }
             "lseek" => {
-                let [fd, offset, whence] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, offset, whence] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
                 let whence = this.read_scalar(whence)?.to_i32()?;
@@ -291,39 +292,36 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(result, dest)?;
             }
             "ftruncate64" => {
-                let [fd, length] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, length] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let length = this.read_scalar(length)?.to_i64()?;
                 let result = this.ftruncate64(fd, length.into())?;
                 this.write_scalar(result, dest)?;
             }
             "ftruncate" => {
-                let [fd, length] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, length] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let length = this.read_scalar(length)?.to_int(this.libc_ty_layout("off_t").size)?;
                 let result = this.ftruncate64(fd, length)?;
                 this.write_scalar(result, dest)?;
             }
             "fsync" => {
-                let [fd] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.fsync(fd)?;
                 this.write_scalar(result, dest)?;
             }
             "fdatasync" => {
-                let [fd] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.fdatasync(fd)?;
                 this.write_scalar(result, dest)?;
             }
             "readlink" => {
-                let [pathname, buf, bufsize] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [pathname, buf, bufsize] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.readlink(pathname, buf, bufsize)?;
                 this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
             }
             "posix_fadvise" => {
-                let [fd, offset, len, advice] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, offset, len, advice] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.read_scalar(fd)?.to_i32()?;
                 this.read_target_isize(offset)?;
                 this.read_target_isize(len)?;
@@ -332,12 +330,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_null(dest)?;
             }
             "realpath" => {
-                let [path, resolved_path] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [path, resolved_path] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.realpath(path, resolved_path)?;
                 this.write_scalar(result, dest)?;
             }
             "mkstemp" => {
-                let [template] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [template] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.mkstemp(template)?;
                 this.write_scalar(result, dest)?;
             }
@@ -345,63 +343,59 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Unnamed sockets and pipes
             "socketpair" => {
                 let [domain, type_, protocol, sv] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                    this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.socketpair(domain, type_, protocol, sv)?;
                 this.write_scalar(result, dest)?;
             }
             "pipe" => {
-                let [pipefd] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [pipefd] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.pipe2(pipefd, /*flags*/ None)?;
                 this.write_scalar(result, dest)?;
             }
             "pipe2" => {
                 // Currently this function does not exist on all Unixes, e.g. on macOS.
-                if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "solaris" | "illumos") {
-                    throw_unsup_format!(
-                        "`pipe2` is not supported on {}",
-                        this.tcx.sess.target.os
-                    );
+                if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "solaris" | "illumos")
+                {
+                    throw_unsup_format!("`pipe2` is not supported on {}", this.tcx.sess.target.os);
                 }
-                let [pipefd, flags] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [pipefd, flags] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.pipe2(pipefd, Some(flags))?;
                 this.write_scalar(result, dest)?;
             }
 
             // Time
             "gettimeofday" => {
-                let [tv, tz] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [tv, tz] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.gettimeofday(tv, tz)?;
                 this.write_scalar(result, dest)?;
             }
             "localtime_r" => {
-                let [timep, result_op] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [timep, result_op] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.localtime_r(timep, result_op)?;
                 this.write_pointer(result, dest)?;
             }
             "clock_gettime" => {
-                let [clk_id, tp] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [clk_id, tp] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.clock_gettime(clk_id, tp)?;
                 this.write_scalar(result, dest)?;
             }
 
             // Allocation
             "posix_memalign" => {
-                let [memptr, align, size] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [memptr, align, size] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.posix_memalign(memptr, align, size)?;
                 this.write_scalar(result, dest)?;
             }
 
             "mmap" => {
-                let [addr, length, prot, flags, fd, offset] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [addr, length, prot, flags, fd, offset] =
+                    this.check_shim(abi, Conv::C, link_name, args)?;
                 let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
                 let ptr = this.mmap(addr, length, prot, flags, fd, offset)?;
                 this.write_scalar(ptr, dest)?;
             }
             "munmap" => {
-                let [addr, length] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [addr, length] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.munmap(addr, length)?;
                 this.write_scalar(result, dest)?;
             }
@@ -414,8 +408,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         this.tcx.sess.target.os
                     );
                 }
-                let [ptr, nmemb, size] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [ptr, nmemb, size] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let nmemb = this.read_target_usize(nmemb)?;
                 let size = this.read_target_usize(size)?;
@@ -438,19 +431,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "aligned_alloc" => {
                 // This is a C11 function, we assume all Unixes have it.
                 // (MSVC explicitly does not support this.)
-                let [align, size] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [align, size] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let res = this.aligned_alloc(align, size)?;
                 this.write_pointer(res, dest)?;
             }
 
             // Dynamic symbol loading
             "dlsym" => {
-                let [handle, symbol] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [handle, symbol] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.read_target_usize(handle)?;
                 let symbol = this.read_pointer(symbol)?;
                 let name = this.read_c_str(symbol)?;
-                if let Ok(name) = str::from_utf8(name) && is_dyn_sym(name, &this.tcx.sess.target.os) {
+                if let Ok(name) = str::from_utf8(name)
+                    && is_dyn_sym(name, &this.tcx.sess.target.os)
+                {
                     let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
                     this.write_pointer(ptr, dest)?;
                 } else {
@@ -460,7 +454,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Thread-local storage
             "pthread_key_create" => {
-                let [key, dtor] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [key, dtor] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let key_place = this.deref_pointer_as(key, this.libc_ty_layout("pthread_key_t"))?;
                 let dtor = this.read_pointer(dtor)?;
 
@@ -488,21 +482,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_null(dest)?;
             }
             "pthread_key_delete" => {
-                let [key] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [key] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
                 this.machine.tls.delete_tls_key(key)?;
                 // Return success (0)
                 this.write_null(dest)?;
             }
             "pthread_getspecific" => {
-                let [key] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [key] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
                 let active_thread = this.active_thread();
                 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
                 this.write_scalar(ptr, dest)?;
             }
             "pthread_setspecific" => {
-                let [key, new_ptr] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [key, new_ptr] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
                 let active_thread = this.active_thread();
                 let new_data = this.read_scalar(new_ptr)?;
@@ -514,151 +508,149 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Synchronization primitives
             "pthread_mutexattr_init" => {
-                let [attr] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [attr] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_mutexattr_init(attr)?;
                 this.write_null(dest)?;
             }
             "pthread_mutexattr_settype" => {
-                let [attr, kind] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [attr, kind] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.pthread_mutexattr_settype(attr, kind)?;
                 this.write_scalar(result, dest)?;
             }
             "pthread_mutexattr_destroy" => {
-                let [attr] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [attr] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_mutexattr_destroy(attr)?;
                 this.write_null(dest)?;
             }
             "pthread_mutex_init" => {
-                let [mutex, attr] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [mutex, attr] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_mutex_init(mutex, attr)?;
                 this.write_null(dest)?;
             }
             "pthread_mutex_lock" => {
-                let [mutex] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_mutex_lock(mutex, dest)?;
             }
             "pthread_mutex_trylock" => {
-                let [mutex] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.pthread_mutex_trylock(mutex)?;
                 this.write_scalar(result, dest)?;
             }
             "pthread_mutex_unlock" => {
-                let [mutex] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.pthread_mutex_unlock(mutex)?;
                 this.write_scalar(result, dest)?;
             }
             "pthread_mutex_destroy" => {
-                let [mutex] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_mutex_destroy(mutex)?;
                 this.write_int(0, dest)?;
             }
             "pthread_rwlock_rdlock" => {
-                let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_rwlock_rdlock(rwlock, dest)?;
             }
             "pthread_rwlock_tryrdlock" => {
-                let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.pthread_rwlock_tryrdlock(rwlock)?;
                 this.write_scalar(result, dest)?;
             }
             "pthread_rwlock_wrlock" => {
-                let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_rwlock_wrlock(rwlock, dest)?;
             }
             "pthread_rwlock_trywrlock" => {
-                let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.pthread_rwlock_trywrlock(rwlock)?;
                 this.write_scalar(result, dest)?;
             }
             "pthread_rwlock_unlock" => {
-                let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_rwlock_unlock(rwlock)?;
                 this.write_null(dest)?;
             }
             "pthread_rwlock_destroy" => {
-                let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_rwlock_destroy(rwlock)?;
                 this.write_null(dest)?;
             }
             "pthread_condattr_init" => {
-                let [attr] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [attr] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_condattr_init(attr)?;
                 this.write_null(dest)?;
             }
             "pthread_condattr_setclock" => {
-                let [attr, clock_id] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [attr, clock_id] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.pthread_condattr_setclock(attr, clock_id)?;
                 this.write_scalar(result, dest)?;
             }
             "pthread_condattr_getclock" => {
-                let [attr, clock_id] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [attr, clock_id] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_condattr_getclock(attr, clock_id)?;
                 this.write_null(dest)?;
             }
             "pthread_condattr_destroy" => {
-                let [attr] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [attr] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_condattr_destroy(attr)?;
                 this.write_null(dest)?;
             }
             "pthread_cond_init" => {
-                let [cond, attr] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [cond, attr] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_cond_init(cond, attr)?;
                 this.write_null(dest)?;
             }
             "pthread_cond_signal" => {
-                let [cond] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [cond] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_cond_signal(cond)?;
                 this.write_null(dest)?;
             }
             "pthread_cond_broadcast" => {
-                let [cond] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [cond] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_cond_broadcast(cond)?;
                 this.write_null(dest)?;
             }
             "pthread_cond_wait" => {
-                let [cond, mutex] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [cond, mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_cond_wait(cond, mutex, dest)?;
             }
             "pthread_cond_timedwait" => {
-                let [cond, mutex, abstime] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [cond, mutex, abstime] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_cond_timedwait(cond, mutex, abstime, dest)?;
             }
             "pthread_cond_destroy" => {
-                let [cond] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [cond] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_cond_destroy(cond)?;
                 this.write_null(dest)?;
             }
 
             // Threading
             "pthread_create" => {
-                let [thread, attr, start, arg] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [thread, attr, start, arg] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_create(thread, attr, start, arg)?;
                 this.write_null(dest)?;
             }
             "pthread_join" => {
-                let [thread, retval] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [thread, retval] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let res = this.pthread_join(thread, retval)?;
                 this.write_scalar(res, dest)?;
             }
             "pthread_detach" => {
-                let [thread] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [thread] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let res = this.pthread_detach(thread)?;
                 this.write_scalar(res, dest)?;
             }
             "pthread_self" => {
-                let [] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let res = this.pthread_self()?;
                 this.write_scalar(res, dest)?;
             }
             "sched_yield" => {
-                let [] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.sched_yield()?;
                 this.write_null(dest)?;
             }
             "nanosleep" => {
-                let [req, rem] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [req, rem] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.nanosleep(req, rem)?;
                 this.write_scalar(result, dest)?;
             }
@@ -671,8 +663,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     );
                 }
 
-                let [pid, cpusetsize, mask] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [pid, cpusetsize, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let pid = this.read_scalar(pid)?.to_u32()?;
                 let cpusetsize = this.read_target_usize(cpusetsize)?;
                 let mask = this.read_pointer(mask)?;
@@ -680,7 +671,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // TODO: when https://github.com/rust-lang/miri/issues/3730 is fixed this should use its notion of tid/pid
                 let thread_id = match pid {
                     0 => this.active_thread(),
-                    _ => throw_unsup_format!("`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread)"),
+                    _ =>
+                        throw_unsup_format!(
+                            "`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread)"
+                        ),
                 };
 
                 // The mask is stored in chunks, and the size must be a whole number of chunks.
@@ -694,7 +688,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) {
                     let cpuset = cpuset.clone();
                     // we only copy whole chunks of size_of::<c_ulong>()
-                    let byte_count = Ord::min(cpuset.as_slice().len(), cpusetsize.try_into().unwrap());
+                    let byte_count =
+                        Ord::min(cpuset.as_slice().len(), cpusetsize.try_into().unwrap());
                     this.write_bytes_ptr(mask, cpuset.as_slice()[..byte_count].iter().copied())?;
                     this.write_null(dest)?;
                 } else {
@@ -711,8 +706,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     );
                 }
 
-                let [pid, cpusetsize, mask] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [pid, cpusetsize, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let pid = this.read_scalar(pid)?.to_u32()?;
                 let cpusetsize = this.read_target_usize(cpusetsize)?;
                 let mask = this.read_pointer(mask)?;
@@ -720,7 +714,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // TODO: when https://github.com/rust-lang/miri/issues/3730 is fixed this should use its notion of tid/pid
                 let thread_id = match pid {
                     0 => this.active_thread(),
-                    _ => throw_unsup_format!("`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread)"),
+                    _ =>
+                        throw_unsup_format!(
+                            "`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread)"
+                        ),
                 };
 
                 if this.ptr_is_null(mask)? {
@@ -729,7 +726,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     // NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`.
                     // Any unspecified bytes are treated as zero here (none of the CPUs are configured).
                     // This is not exactly documented, so we assume that this is the behavior in practice.
-                    let bits_slice = this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?;
+                    let bits_slice =
+                        this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?;
                     // This ignores the bytes beyond `CpuAffinityMask::CPU_MASK_BYTES`
                     let bits_array: [u8; CpuAffinityMask::CPU_MASK_BYTES] =
                         std::array::from_fn(|i| bits_slice.get(i).copied().unwrap_or(0));
@@ -748,12 +746,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Miscellaneous
             "isatty" => {
-                let [fd] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.isatty(fd)?;
                 this.write_scalar(result, dest)?;
             }
             "pthread_atfork" => {
-                let [prepare, parent, child] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [prepare, parent, child] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.read_pointer(prepare)?;
                 this.read_pointer(parent)?;
                 this.read_pointer(child)?;
@@ -763,15 +761,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "getentropy" => {
                 // This function is non-standard but exists with the same signature and behavior on
                 // Linux, macOS, FreeBSD and Solaris/Illumos.
-                if !matches!(&*this.tcx.sess.target.os, "linux" | "macos" | "freebsd" | "illumos" | "solaris" | "android") {
+                if !matches!(
+                    &*this.tcx.sess.target.os,
+                    "linux" | "macos" | "freebsd" | "illumos" | "solaris" | "android"
+                ) {
                     throw_unsup_format!(
                         "`getentropy` is not supported on {}",
                         this.tcx.sess.target.os
                     );
                 }
 
-                let [buf, bufsize] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [buf, bufsize] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let buf = this.read_pointer(buf)?;
                 let bufsize = this.read_target_usize(bufsize)?;
 
@@ -789,8 +789,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
 
             "strerror_r" => {
-                let [errnum, buf, buflen] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                let [errnum, buf, buflen] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.strerror_r(errnum, buf, buflen)?;
                 this.write_scalar(result, dest)?;
             }
@@ -798,14 +797,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "getrandom" => {
                 // This function is non-standard but exists with the same signature and behavior on
                 // Linux, FreeBSD and Solaris/Illumos.
-                if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "illumos" | "solaris" | "android") {
+                if !matches!(
+                    &*this.tcx.sess.target.os,
+                    "linux" | "freebsd" | "illumos" | "solaris" | "android"
+                ) {
                     throw_unsup_format!(
                         "`getrandom` is not supported on {}",
                         this.tcx.sess.target.os
                     );
                 }
-                let [ptr, len, flags] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [ptr, len, flags] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let len = this.read_target_usize(len)?;
                 let _flags = this.read_scalar(flags)?.to_i32()?;
@@ -822,7 +823,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         this.tcx.sess.target.os
                     );
                 }
-                let [ptr, len] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [ptr, len] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let len = this.read_target_usize(len)?;
                 this.gen_random(ptr, len)?;
@@ -841,7 +842,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // For arm32 they did something custom, but similar enough that the same
                 // `_Unwind_RaiseException` impl in miri should work:
                 // https://github.com/ARM-software/abi-aa/blob/main/ehabi32/ehabi32.rst
-                if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "illumos" | "solaris" | "android" | "macos") {
+                if !matches!(
+                    &*this.tcx.sess.target.os,
+                    "linux" | "freebsd" | "illumos" | "solaris" | "android" | "macos"
+                ) {
                     throw_unsup_format!(
                         "`_Unwind_RaiseException` is not supported on {}",
                         this.tcx.sess.target.os
@@ -853,43 +857,42 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 return interp_ok(EmulateItemResult::NeedsUnwind);
             }
             "getuid" => {
-                let [] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
                 // For now, just pretend we always have this fixed UID.
                 this.write_int(UID, dest)?;
             }
 
             // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
             // These shims are enabled only when the caller is in the standard library.
-            "pthread_attr_getguardsize"
-            if this.frame_in_std() => {
-                let [_attr, guard_size] = this.check_shim(abi, Conv::C , link_name, args)?;
+            "pthread_attr_getguardsize" if this.frame_in_std() => {
+                let [_attr, guard_size] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let guard_size = this.deref_pointer(guard_size)?;
                 let guard_size_layout = this.libc_ty_layout("size_t");
-                this.write_scalar(Scalar::from_uint(this.machine.page_size, guard_size_layout.size), &guard_size)?;
+                this.write_scalar(
+                    Scalar::from_uint(this.machine.page_size, guard_size_layout.size),
+                    &guard_size,
+                )?;
 
                 // Return success (`0`).
                 this.write_null(dest)?;
             }
 
-            | "pthread_attr_init"
-            | "pthread_attr_destroy"
-            if this.frame_in_std() => {
-                let [_] = this.check_shim(abi, Conv::C , link_name, args)?;
+            "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => {
+                let [_] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.write_null(dest)?;
             }
-            | "pthread_attr_setstacksize"
-            if this.frame_in_std() => {
-                let [_, _] = this.check_shim(abi, Conv::C , link_name, args)?;
+            "pthread_attr_setstacksize" if this.frame_in_std() => {
+                let [_, _] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.write_null(dest)?;
             }
 
-            "pthread_attr_getstack"
-            if this.frame_in_std() => {
+            "pthread_attr_getstack" if this.frame_in_std() => {
                 // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here.
                 // Hence we can mostly ignore the input `attr_place`.
                 let [attr_place, addr_place, size_place] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
-                let _attr_place = this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?;
+                    this.check_shim(abi, Conv::C, link_name, args)?;
+                let _attr_place =
+                    this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?;
                 let addr_place = this.deref_pointer(addr_place)?;
                 let size_place = this.deref_pointer(size_place)?;
 
@@ -906,24 +909,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_null(dest)?;
             }
 
-            | "signal"
-            | "sigaltstack"
-            if this.frame_in_std() => {
-                let [_, _] = this.check_shim(abi, Conv::C , link_name, args)?;
+            "signal" | "sigaltstack" if this.frame_in_std() => {
+                let [_, _] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.write_null(dest)?;
             }
-            | "sigaction"
-            | "mprotect"
-            if this.frame_in_std() => {
-                let [_, _, _] = this.check_shim(abi, Conv::C , link_name, args)?;
+            "sigaction" | "mprotect" if this.frame_in_std() => {
+                let [_, _, _] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.write_null(dest)?;
             }
 
-            "getpwuid_r" | "__posix_getpwuid_r"
-            if this.frame_in_std() => {
+            "getpwuid_r" | "__posix_getpwuid_r" if this.frame_in_std() => {
                 // getpwuid_r is the standard name, __posix_getpwuid_r is used on solarish
                 let [uid, pwd, buf, buflen, result] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                    this.check_shim(abi, Conv::C, link_name, args)?;
                 this.check_no_isolation("`getpwuid_r`")?;
 
                 let uid = this.read_scalar(uid)?.to_u32()?;
@@ -961,11 +959,26 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             _ => {
                 let target_os = &*this.tcx.sess.target.os;
                 return match target_os {
-                    "android" => android::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
-                    "freebsd" => freebsd::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
-                    "linux" => linux::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
-                    "macos" => macos::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
-                    "solaris" | "illumos" => solarish::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
+                    "android" =>
+                        android::EvalContextExt::emulate_foreign_item_inner(
+                            this, link_name, abi, args, dest,
+                        ),
+                    "freebsd" =>
+                        freebsd::EvalContextExt::emulate_foreign_item_inner(
+                            this, link_name, abi, args, dest,
+                        ),
+                    "linux" =>
+                        linux::EvalContextExt::emulate_foreign_item_inner(
+                            this, link_name, abi, args, dest,
+                        ),
+                    "macos" =>
+                        macos::EvalContextExt::emulate_foreign_item_inner(
+                            this, link_name, abi, args, dest,
+                        ),
+                    "solaris" | "illumos" =>
+                        solarish::EvalContextExt::emulate_foreign_item_inner(
+                            this, link_name, abi, args, dest,
+                        ),
                     _ => interp_ok(EmulateItemResult::NotSupported),
                 };
             }
diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
index 5381234e28c..03dbd931329 100644
--- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
@@ -21,29 +21,38 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
         match link_name.as_str() {
             // Threading
-            "pthread_set_name_np" => {
+            "pthread_setname_np" => {
                 let [thread, name] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let max_len = usize::MAX; // FreeBSD does not seem to have a limit.
-                // FreeBSD's pthread_set_name_np does not return anything.
-                this.pthread_setname_np(
+                let res = match this.pthread_setname_np(
                     this.read_scalar(thread)?,
                     this.read_scalar(name)?,
                     max_len,
                     /* truncate */ false,
-                )?;
+                )? {
+                    ThreadNameResult::Ok => Scalar::from_u32(0),
+                    ThreadNameResult::NameTooLong => unreachable!(),
+                    ThreadNameResult::ThreadNotFound => this.eval_libc("ESRCH"),
+                };
+                this.write_scalar(res, dest)?;
             }
-            "pthread_get_name_np" => {
+            "pthread_getname_np" => {
                 let [thread, name, len] = this.check_shim(abi, Conv::C, link_name, args)?;
-                // FreeBSD's pthread_get_name_np does not return anything
-                // and uses strlcpy, which truncates the resulting value,
+                // FreeBSD's pthread_getname_np uses strlcpy, which truncates the resulting value,
                 // but always adds a null terminator (except for zero-sized buffers).
                 // https://github.com/freebsd/freebsd-src/blob/c2d93a803acef634bd0eede6673aeea59e90c277/lib/libthr/thread/thr_info.c#L119-L144
-                this.pthread_getname_np(
+                let res = match this.pthread_getname_np(
                     this.read_scalar(thread)?,
                     this.read_scalar(name)?,
                     this.read_scalar(len)?,
                     /* truncate */ true,
-                )?;
+                )? {
+                    ThreadNameResult::Ok => Scalar::from_u32(0),
+                    // `NameTooLong` is possible when the buffer is zero sized,
+                    ThreadNameResult::NameTooLong => Scalar::from_u32(0),
+                    ThreadNameResult::ThreadNotFound => this.eval_libc("ESRCH"),
+                };
+                this.write_scalar(res, dest)?;
             }
 
             // File related shims
diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs
index 5682fb659e7..25594b78031 100644
--- a/src/tools/miri/src/shims/unix/fs.rs
+++ b/src/tools/miri/src/shims/unix/fs.rs
@@ -31,8 +31,7 @@ impl FileDescription for FileHandle {
     }
 
     fn read<'tcx>(
-        &self,
-        _self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
@@ -49,8 +48,7 @@ impl FileDescription for FileHandle {
     }
 
     fn write<'tcx>(
-        &self,
-        _self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
@@ -76,7 +74,7 @@ impl FileDescription for FileHandle {
     }
 
     fn close<'tcx>(
-        self: Box<Self>,
+        self,
         communicate_allowed: bool,
         _ecx: &mut MiriInterpCx<'tcx>,
     ) -> InterpResult<'tcx, io::Result<()>> {
@@ -87,7 +85,7 @@ impl FileDescription for FileHandle {
             // to handle possible errors correctly.
             let result = self.file.sync_all();
             // Now we actually close the file and return the result.
-            drop(*self);
+            drop(self.file);
             interp_ok(result)
         } else {
             // We drop the file, this closes it but ignores any errors
@@ -96,7 +94,7 @@ impl FileDescription for FileHandle {
             // `/dev/urandom` which are read-only. Check
             // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439
             // for a deeper discussion.
-            drop(*self);
+            drop(self.file);
             interp_ok(Ok(()))
         }
     }
@@ -1311,22 +1309,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         };
 
         // FIXME: Support ftruncate64 for all FDs
-        let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
+        let file = fd.downcast::<FileHandle>().ok_or_else(|| {
             err_unsup_format!("`ftruncate64` is only supported on file-backed file descriptors")
         })?;
 
-        if *writable {
+        if file.writable {
             if let Ok(length) = length.try_into() {
-                let result = file.set_len(length);
-                drop(fd);
+                let result = file.file.set_len(length);
                 let result = this.try_unwrap_io_result(result.map(|_| 0i32))?;
                 interp_ok(Scalar::from_i32(result))
             } else {
-                drop(fd);
                 this.set_last_error_and_return_i32(LibcError("EINVAL"))
             }
         } else {
-            drop(fd);
             // The file is not writable
             this.set_last_error_and_return_i32(LibcError("EINVAL"))
         }
@@ -1358,11 +1353,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
         // Only regular files support synchronization.
-        let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
+        let file = fd.downcast::<FileHandle>().ok_or_else(|| {
             err_unsup_format!("`fsync` is only supported on file-backed file descriptors")
         })?;
-        let io_result = maybe_sync_file(file, *writable, File::sync_all);
-        drop(fd);
+        let io_result = maybe_sync_file(&file.file, file.writable, File::sync_all);
         interp_ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
     }
 
@@ -1382,11 +1376,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
         // Only regular files support synchronization.
-        let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
+        let file = fd.downcast::<FileHandle>().ok_or_else(|| {
             err_unsup_format!("`fdatasync` is only supported on file-backed file descriptors")
         })?;
-        let io_result = maybe_sync_file(file, *writable, File::sync_data);
-        drop(fd);
+        let io_result = maybe_sync_file(&file.file, file.writable, File::sync_data);
         interp_ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
     }
 
@@ -1425,11 +1418,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
         // Only regular files support synchronization.
-        let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
+        let file = fd.downcast::<FileHandle>().ok_or_else(|| {
             err_unsup_format!("`sync_data_range` is only supported on file-backed file descriptors")
         })?;
-        let io_result = maybe_sync_file(file, *writable, File::sync_data);
-        drop(fd);
+        let io_result = maybe_sync_file(&file.file, file.writable, File::sync_data);
         interp_ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
     }
 
diff --git a/src/tools/miri/src/shims/unix/linux_like/epoll.rs b/src/tools/miri/src/shims/unix/linux_like/epoll.rs
index 5b240351c20..de8bcb54aef 100644
--- a/src/tools/miri/src/shims/unix/linux_like/epoll.rs
+++ b/src/tools/miri/src/shims/unix/linux_like/epoll.rs
@@ -5,12 +5,14 @@ use std::rc::{Rc, Weak};
 use std::time::Duration;
 
 use crate::concurrency::VClock;
-use crate::shims::files::{FdId, FileDescription, FileDescriptionRef, WeakFileDescriptionRef};
+use crate::shims::files::{
+    DynFileDescriptionRef, FdId, FileDescription, FileDescriptionRef, WeakFileDescriptionRef,
+};
 use crate::shims::unix::UnixFileDescription;
 use crate::*;
 
 /// An `Epoll` file descriptor connects file handles and epoll events
-#[derive(Clone, Debug, Default)]
+#[derive(Debug, Default)]
 struct Epoll {
     /// A map of EpollEventInterests registered under this epoll instance.
     /// Each entry is differentiated using FdId and file descriptor value.
@@ -18,11 +20,15 @@ struct Epoll {
     /// A map of EpollEventInstance that will be returned when `epoll_wait` is called.
     /// Similar to interest_list, the entry is also differentiated using FdId
     /// and file descriptor value.
-    // This is an Rc because EpollInterest need to hold a reference to update
-    // it.
-    ready_list: Rc<ReadyList>,
+    ready_list: ReadyList,
     /// A list of thread ids blocked on this epoll instance.
-    thread_id: RefCell<Vec<ThreadId>>,
+    blocked_tid: RefCell<Vec<ThreadId>>,
+}
+
+impl VisitProvenance for Epoll {
+    fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
+        // No provenance anywhere in this type.
+    }
 }
 
 /// EpollEventInstance contains information that will be returned by epoll_wait.
@@ -51,7 +57,7 @@ impl EpollEventInstance {
 /// see the man page:
 ///
 /// <https://man7.org/linux/man-pages/man2/epoll_ctl.2.html>
-#[derive(Clone, Debug)]
+#[derive(Debug)]
 pub struct EpollEventInterest {
     /// The file descriptor value of the file description registered.
     /// This is only used for ready_list, to inform userspace which FD triggered an event.
@@ -65,10 +71,10 @@ pub struct EpollEventInterest {
     /// but only u64 is supported for now.
     /// <https://man7.org/linux/man-pages/man3/epoll_event.3type.html>
     data: u64,
-    /// Ready list of the epoll instance under which this EpollEventInterest is registered.
-    ready_list: Rc<ReadyList>,
     /// The epoll file description that this EpollEventInterest is registered under.
-    weak_epfd: WeakFileDescriptionRef,
+    /// This is weak to avoid cycles, but an upgrade is always guaranteed to succeed
+    /// because only the `Epoll` holds a strong ref to a `EpollEventInterest`.
+    weak_epfd: WeakFileDescriptionRef<Epoll>,
 }
 
 /// EpollReadyEvents reflects the readiness of a file description.
@@ -134,19 +140,13 @@ impl EpollReadyEvents {
     }
 }
 
-impl Epoll {
-    fn get_ready_list(&self) -> Rc<ReadyList> {
-        Rc::clone(&self.ready_list)
-    }
-}
-
 impl FileDescription for Epoll {
     fn name(&self) -> &'static str {
         "epoll"
     }
 
     fn close<'tcx>(
-        self: Box<Self>,
+        self,
         _communicate_allowed: bool,
         _ecx: &mut MiriInterpCx<'tcx>,
     ) -> InterpResult<'tcx, io::Result<()>> {
@@ -271,17 +271,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let Some(epfd) = this.machine.fds.get(epfd_value) else {
             return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
-        let epoll_file_description = epfd
+        let epfd = epfd
             .downcast::<Epoll>()
             .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?;
 
-        let mut interest_list = epoll_file_description.interest_list.borrow_mut();
-        let ready_list = &epoll_file_description.ready_list;
+        let mut interest_list = epfd.interest_list.borrow_mut();
 
         let Some(fd_ref) = this.machine.fds.get(fd) else {
             return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
-        let id = fd_ref.get_id();
+        let id = fd_ref.id();
 
         if op == epoll_ctl_add || op == epoll_ctl_mod {
             // Read event bitmask and data from epoll_event passed by caller.
@@ -337,30 +336,33 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 }
             }
 
-            // Create an epoll_interest.
-            let interest = Rc::new(RefCell::new(EpollEventInterest {
-                fd_num: fd,
-                events,
-                data,
-                ready_list: Rc::clone(ready_list),
-                weak_epfd: epfd.downgrade(),
-            }));
-
             if op == epoll_ctl_add {
+                // Create an epoll_interest.
+                let interest = Rc::new(RefCell::new(EpollEventInterest {
+                    fd_num: fd,
+                    events,
+                    data,
+                    weak_epfd: FileDescriptionRef::downgrade(&epfd),
+                }));
+                // Notification will be returned for current epfd if there is event in the file
+                // descriptor we registered.
+                check_and_update_one_event_interest(&fd_ref, &interest, id, this)?;
+
                 // Insert an epoll_interest to global epoll_interest list.
                 this.machine.epoll_interests.insert_epoll_interest(id, Rc::downgrade(&interest));
-                interest_list.insert(epoll_key, Rc::clone(&interest));
+                interest_list.insert(epoll_key, interest);
             } else {
-                // Directly modify the epoll_interest so the global epoll_event_interest table
-                // will be updated too.
-                let mut epoll_interest = interest_list.get_mut(&epoll_key).unwrap().borrow_mut();
-                epoll_interest.events = events;
-                epoll_interest.data = data;
+                // Modify the existing interest.
+                let epoll_interest = interest_list.get_mut(&epoll_key).unwrap();
+                {
+                    let mut epoll_interest = epoll_interest.borrow_mut();
+                    epoll_interest.events = events;
+                    epoll_interest.data = data;
+                }
+                // Updating an FD interest triggers events.
+                check_and_update_one_event_interest(&fd_ref, epoll_interest, id, this)?;
             }
 
-            // Notification will be returned for current epfd if there is event in the file
-            // descriptor we registered.
-            check_and_update_one_event_interest(&fd_ref, interest, id, this)?;
             interp_ok(Scalar::from_i32(0))
         } else if op == epoll_ctl_del {
             let epoll_key = (id, fd);
@@ -373,7 +375,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             drop(epoll_interest);
 
             // Remove related epoll_interest from ready list.
-            ready_list.mapping.borrow_mut().remove(&epoll_key);
+            epfd.ready_list.mapping.borrow_mut().remove(&epoll_key);
 
             // Remove dangling EpollEventInterest from its global table.
             // .unwrap() below should succeed because the file description id must have registered
@@ -452,24 +454,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let Some(epfd) = this.machine.fds.get(epfd_value) else {
             return this.set_last_error_and_return(LibcError("EBADF"), dest);
         };
-        // Create a weak ref of epfd and pass it to callback so we will make sure that epfd
-        // is not close after the thread unblocks.
-        let weak_epfd = epfd.downgrade();
+        let Some(epfd) = epfd.downcast::<Epoll>() else {
+            return this.set_last_error_and_return(LibcError("EBADF"), dest);
+        };
 
         // We just need to know if the ready list is empty and borrow the thread_ids out.
-        // The whole logic is wrapped inside a block so we don't need to manually drop epfd later.
-        let ready_list_empty;
-        let mut thread_ids;
-        {
-            let epoll_file_description = epfd
-                .downcast::<Epoll>()
-                .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?;
-            ready_list_empty = epoll_file_description.ready_list.mapping.borrow().is_empty();
-            thread_ids = epoll_file_description.thread_id.borrow_mut();
-        }
+        let ready_list_empty = epfd.ready_list.mapping.borrow().is_empty();
         if timeout == 0 || !ready_list_empty {
             // If the ready list is not empty, or the timeout is 0, we can return immediately.
-            return_ready_list(epfd_value, weak_epfd, dest, &event, this)?;
+            return_ready_list(&epfd, dest, &event, this)?;
         } else {
             // Blocking
             let timeout = match timeout {
@@ -484,34 +477,37 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     );
                 }
             };
-            thread_ids.push(this.active_thread());
+            // Record this thread as blocked.
+            epfd.blocked_tid.borrow_mut().push(this.active_thread());
+            // And block it.
             let dest = dest.clone();
+            // We keep a strong ref to the underlying `Epoll` to make sure it sticks around.
+            // This means there'll be a leak if we never wake up, but that anyway would imply
+            // a thread is permanently blocked so this is fine.
             this.block_thread(
                 BlockReason::Epoll,
                 timeout,
                 callback!(
                     @capture<'tcx> {
-                        epfd_value: i32,
-                        weak_epfd: WeakFileDescriptionRef,
+                        epfd: FileDescriptionRef<Epoll>,
                         dest: MPlaceTy<'tcx>,
                         event: MPlaceTy<'tcx>,
                     }
-                    @unblock = |this| {
-                        return_ready_list(epfd_value, weak_epfd, &dest, &event, this)?;
-                        interp_ok(())
-                    }
-                    @timeout = |this| {
-                        // No notification after blocking timeout.
-                        let Some(epfd) = weak_epfd.upgrade() else {
-                            throw_unsup_format!("epoll FD {epfd_value} got closed while blocking.")
-                        };
-                        // Remove the current active thread_id from the blocked thread_id list.
-                        epfd.downcast::<Epoll>()
-                            .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?
-                            .thread_id.borrow_mut()
-                            .retain(|&id| id != this.active_thread());
-                        this.write_int(0, &dest)?;
-                        interp_ok(())
+                    |this, unblock: UnblockKind| {
+                        match unblock {
+                            UnblockKind::Ready => {
+                                return_ready_list(&epfd, &dest, &event, this)?;
+                                interp_ok(())
+                            },
+                            UnblockKind::TimedOut => {
+                                // Remove the current active thread_id from the blocked thread_id list.
+                                epfd
+                                    .blocked_tid.borrow_mut()
+                                    .retain(|&id| id != this.active_thread());
+                                this.write_int(0, &dest)?;
+                                interp_ok(())
+                            },
+                        }
                     }
                 ),
             );
@@ -528,21 +524,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     /// do not call this function when an FD didn't have anything happen to it!
     fn check_and_update_readiness(
         &mut self,
-        fd_ref: &FileDescriptionRef,
+        fd_ref: DynFileDescriptionRef,
     ) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
-        let id = fd_ref.get_id();
+        let id = fd_ref.id();
         let mut waiter = Vec::new();
         // Get a list of EpollEventInterest that is associated to a specific file description.
         if let Some(epoll_interests) = this.machine.epoll_interests.get_epoll_interest(id) {
             for weak_epoll_interest in epoll_interests {
                 if let Some(epoll_interest) = weak_epoll_interest.upgrade() {
-                    let is_updated = check_and_update_one_event_interest(
-                        fd_ref,
-                        epoll_interest.clone(),
-                        id,
-                        this,
-                    )?;
+                    let is_updated =
+                        check_and_update_one_event_interest(&fd_ref, &epoll_interest, id, this)?;
                     if is_updated {
                         // Edge-triggered notification only notify one thread even if there are
                         // multiple threads blocked on the same epfd.
@@ -553,10 +545,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         // holds a strong ref to epoll_interest.
                         let epfd = epoll_interest.borrow().weak_epfd.upgrade().unwrap();
                         // FIXME: We can randomly pick a thread to unblock.
-
-                        let epoll = epfd.downcast::<Epoll>().unwrap();
-
-                        if let Some(thread_id) = epoll.thread_id.borrow_mut().pop() {
+                        if let Some(thread_id) = epfd.blocked_tid.borrow_mut().pop() {
                             waiter.push(thread_id);
                         };
                     }
@@ -595,14 +584,15 @@ fn ready_list_next(
 /// notification was added/updated. Unlike check_and_update_readiness, this function sends a
 /// notification to only one epoll instance.
 fn check_and_update_one_event_interest<'tcx>(
-    fd_ref: &FileDescriptionRef,
-    interest: Rc<RefCell<EpollEventInterest>>,
+    fd_ref: &DynFileDescriptionRef,
+    interest: &RefCell<EpollEventInterest>,
     id: FdId,
     ecx: &MiriInterpCx<'tcx>,
 ) -> InterpResult<'tcx, bool> {
     // Get the bitmask of ready events for a file description.
     let ready_events_bitmask = fd_ref.as_unix().get_epoll_ready_events()?.get_event_bitmask(ecx);
     let epoll_event_interest = interest.borrow();
+    let epfd = epoll_event_interest.weak_epfd.upgrade().unwrap();
     // This checks if any of the events specified in epoll_event_interest.events
     // match those in ready_events.
     let flags = epoll_event_interest.events & ready_events_bitmask;
@@ -610,7 +600,7 @@ fn check_and_update_one_event_interest<'tcx>(
     // insert an epoll_return to the ready list.
     if flags != 0 {
         let epoll_key = (id, epoll_event_interest.fd_num);
-        let ready_list = &mut epoll_event_interest.ready_list.mapping.borrow_mut();
+        let mut ready_list = epfd.ready_list.mapping.borrow_mut();
         let mut event_instance = EpollEventInstance::new(flags, epoll_event_interest.data);
         // If we are tracking data races, remember the current clock so we can sync with it later.
         ecx.release_clock(|clock| {
@@ -627,23 +617,12 @@ fn check_and_update_one_event_interest<'tcx>(
 /// Stores the ready list of the `epfd` epoll instance into `events` (which must be an array),
 /// and the number of returned events into `dest`.
 fn return_ready_list<'tcx>(
-    epfd_value: i32,
-    weak_epfd: WeakFileDescriptionRef,
+    epfd: &FileDescriptionRef<Epoll>,
     dest: &MPlaceTy<'tcx>,
     events: &MPlaceTy<'tcx>,
     ecx: &mut MiriInterpCx<'tcx>,
 ) -> InterpResult<'tcx> {
-    let Some(epfd) = weak_epfd.upgrade() else {
-        throw_unsup_format!("epoll FD {epfd_value} got closed while blocking.")
-    };
-
-    let epoll_file_description = epfd
-        .downcast::<Epoll>()
-        .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?;
-
-    let ready_list = epoll_file_description.get_ready_list();
-
-    let mut ready_list = ready_list.mapping.borrow_mut();
+    let mut ready_list = epfd.ready_list.mapping.borrow_mut();
     let mut num_of_events: i32 = 0;
     let mut array_iter = ecx.project_array_fields(events)?;
 
diff --git a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs
index 4bbe417ea8d..4b76bbb2b4d 100644
--- a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs
+++ b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs
@@ -20,7 +20,7 @@ const MAX_COUNTER: u64 = u64::MAX - 1;
 ///
 /// <https://man.netbsd.org/eventfd.2>
 #[derive(Debug)]
-struct Event {
+struct EventFd {
     /// The object contains an unsigned 64-bit integer (uint64_t) counter that is maintained by the
     /// kernel. This counter is initialized with the value specified in the argument initval.
     counter: Cell<u64>,
@@ -32,13 +32,13 @@ struct Event {
     blocked_write_tid: RefCell<Vec<ThreadId>>,
 }
 
-impl FileDescription for Event {
+impl FileDescription for EventFd {
     fn name(&self) -> &'static str {
         "event"
     }
 
     fn close<'tcx>(
-        self: Box<Self>,
+        self,
         _communicate_allowed: bool,
         _ecx: &mut MiriInterpCx<'tcx>,
     ) -> InterpResult<'tcx, io::Result<()>> {
@@ -47,8 +47,7 @@ impl FileDescription for Event {
 
     /// Read the counter in the buffer and return the counter if succeeded.
     fn read<'tcx>(
-        &self,
-        self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         _communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
@@ -62,11 +61,10 @@ impl FileDescription for Event {
             return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest);
         }
 
-        // eventfd read at the size of u64.
+        // Turn the pointer into a place at the right type.
         let buf_place = ecx.ptr_to_mplace_unaligned(ptr, ty);
 
-        let weak_eventfd = self_ref.downgrade();
-        eventfd_read(buf_place, dest, weak_eventfd, ecx)
+        eventfd_read(buf_place, dest, self, ecx)
     }
 
     /// A write call adds the 8-byte integer value supplied in
@@ -82,8 +80,7 @@ impl FileDescription for Event {
     /// supplied buffer is less than 8 bytes, or if an attempt is
     /// made to write the value 0xffffffffffffffff.
     fn write<'tcx>(
-        &self,
-        self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         _communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
@@ -97,18 +94,10 @@ impl FileDescription for Event {
             return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest);
         }
 
-        // Read the user-supplied value from the pointer.
+        // Turn the pointer into a place at the right type.
         let buf_place = ecx.ptr_to_mplace_unaligned(ptr, ty);
-        let num = ecx.read_scalar(&buf_place)?.to_u64()?;
 
-        // u64::MAX as input is invalid because the maximum value of counter is u64::MAX - 1.
-        if num == u64::MAX {
-            return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest);
-        }
-        // If the addition does not let the counter to exceed the maximum value, update the counter.
-        // Else, block.
-        let weak_eventfd = self_ref.downgrade();
-        eventfd_write(num, buf_place, dest, weak_eventfd, ecx)
+        eventfd_write(buf_place, dest, self, ecx)
     }
 
     fn as_unix(&self) -> &dyn UnixFileDescription {
@@ -116,7 +105,7 @@ impl FileDescription for Event {
     }
 }
 
-impl UnixFileDescription for Event {
+impl UnixFileDescription for EventFd {
     fn get_epoll_ready_events<'tcx>(&self) -> InterpResult<'tcx, EpollReadyEvents> {
         // We only check the status of EPOLLIN and EPOLLOUT flags for eventfd. If other event flags
         // need to be supported in the future, the check should be added here.
@@ -178,7 +167,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let fds = &mut this.machine.fds;
 
-        let fd_value = fds.insert_new(Event {
+        let fd_value = fds.insert_new(EventFd {
             counter: Cell::new(val.into()),
             is_nonblock,
             clock: RefCell::new(VClock::default()),
@@ -193,19 +182,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 /// Block thread if the value addition will exceed u64::MAX -1,
 /// else just add the user-supplied value to current counter.
 fn eventfd_write<'tcx>(
-    num: u64,
     buf_place: MPlaceTy<'tcx>,
     dest: &MPlaceTy<'tcx>,
-    weak_eventfd: WeakFileDescriptionRef,
+    eventfd: FileDescriptionRef<EventFd>,
     ecx: &mut MiriInterpCx<'tcx>,
 ) -> InterpResult<'tcx> {
-    let Some(eventfd_ref) = weak_eventfd.upgrade() else {
-        throw_unsup_format!("eventfd FD got closed while blocking.")
-    };
-
-    // Since we pass the weak file description ref, it is guaranteed to be
-    // an eventfd file description.
-    let eventfd = eventfd_ref.downcast::<Event>().unwrap();
+    // Figure out which value we should add.
+    let num = ecx.read_scalar(&buf_place)?.to_u64()?;
+    // u64::MAX as input is invalid because the maximum value of counter is u64::MAX - 1.
+    if num == u64::MAX {
+        return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest);
+    }
 
     match eventfd.counter.get().checked_add(num) {
         Some(new_count @ 0..=MAX_COUNTER) => {
@@ -217,10 +204,6 @@ fn eventfd_write<'tcx>(
             // Store new counter value.
             eventfd.counter.set(new_count);
 
-            // The state changed; we check and update the status of all supported event
-            // types for current file description.
-            ecx.check_and_update_readiness(&eventfd_ref)?;
-
             // Unblock *all* threads previously blocked on `read`.
             // We need to take out the blocked thread ids and unblock them together,
             // because `unblock_threads` may block them again and end up re-adding the
@@ -231,6 +214,10 @@ fn eventfd_write<'tcx>(
                 ecx.unblock_thread(thread_id, BlockReason::Eventfd)?;
             }
 
+            // The state changed; we check and update the status of all supported event
+            // types for current file description.
+            ecx.check_and_update_readiness(eventfd)?;
+
             // Return how many bytes we consumed from the user-provided buffer.
             return ecx.write_int(buf_place.layout.size.bytes(), dest);
         }
@@ -244,6 +231,7 @@ fn eventfd_write<'tcx>(
 
             eventfd.blocked_write_tid.borrow_mut().push(ecx.active_thread());
 
+            let weak_eventfd = FileDescriptionRef::downgrade(&eventfd);
             ecx.block_thread(
                 BlockReason::Eventfd,
                 None,
@@ -252,11 +240,14 @@ fn eventfd_write<'tcx>(
                         num: u64,
                         buf_place: MPlaceTy<'tcx>,
                         dest: MPlaceTy<'tcx>,
-                        weak_eventfd: WeakFileDescriptionRef,
+                        weak_eventfd: WeakFileDescriptionRef<EventFd>,
                     }
-                    @unblock = |this| {
-                        // When we get unblocked, try again.
-                        eventfd_write(num, buf_place, &dest, weak_eventfd, this)
+                    |this, unblock: UnblockKind| {
+                        assert_eq!(unblock, UnblockKind::Ready);
+                        // When we get unblocked, try again. We know the ref is still valid,
+                        // otherwise there couldn't be a `write` that unblocks us.
+                        let eventfd_ref = weak_eventfd.upgrade().unwrap();
+                        eventfd_write(buf_place, &dest, eventfd_ref, this)
                     }
                 ),
             );
@@ -270,17 +261,9 @@ fn eventfd_write<'tcx>(
 fn eventfd_read<'tcx>(
     buf_place: MPlaceTy<'tcx>,
     dest: &MPlaceTy<'tcx>,
-    weak_eventfd: WeakFileDescriptionRef,
+    eventfd: FileDescriptionRef<EventFd>,
     ecx: &mut MiriInterpCx<'tcx>,
 ) -> InterpResult<'tcx> {
-    let Some(eventfd_ref) = weak_eventfd.upgrade() else {
-        throw_unsup_format!("eventfd FD got closed while blocking.")
-    };
-
-    // Since we pass the weak file description ref to the callback function, it is guaranteed to be
-    // an eventfd file description.
-    let eventfd = eventfd_ref.downcast::<Event>().unwrap();
-
     // Set counter to 0, get old value.
     let counter = eventfd.counter.replace(0);
 
@@ -293,6 +276,7 @@ fn eventfd_read<'tcx>(
 
         eventfd.blocked_read_tid.borrow_mut().push(ecx.active_thread());
 
+        let weak_eventfd = FileDescriptionRef::downgrade(&eventfd);
         ecx.block_thread(
             BlockReason::Eventfd,
             None,
@@ -300,11 +284,14 @@ fn eventfd_read<'tcx>(
                 @capture<'tcx> {
                     buf_place: MPlaceTy<'tcx>,
                     dest: MPlaceTy<'tcx>,
-                    weak_eventfd: WeakFileDescriptionRef,
+                    weak_eventfd: WeakFileDescriptionRef<EventFd>,
                 }
-                @unblock = |this| {
-                    // When we get unblocked, try again.
-                    eventfd_read(buf_place, &dest, weak_eventfd, this)
+                |this, unblock: UnblockKind| {
+                    assert_eq!(unblock, UnblockKind::Ready);
+                    // When we get unblocked, try again. We know the ref is still valid,
+                    // otherwise there couldn't be a `write` that unblocks us.
+                    let eventfd_ref = weak_eventfd.upgrade().unwrap();
+                    eventfd_read(buf_place, &dest, eventfd_ref, this)
                 }
             ),
         );
@@ -315,10 +302,6 @@ fn eventfd_read<'tcx>(
         // Return old counter value into user-space buffer.
         ecx.write_int(counter, &buf_place)?;
 
-        // The state changed; we check and update the status of all supported event
-        // types for current file description.
-        ecx.check_and_update_readiness(&eventfd_ref)?;
-
         // Unblock *all* threads previously blocked on `write`.
         // We need to take out the blocked thread ids and unblock them together,
         // because `unblock_threads` may block them again and end up re-adding the
@@ -329,6 +312,10 @@ fn eventfd_read<'tcx>(
             ecx.unblock_thread(thread_id, BlockReason::Eventfd)?;
         }
 
+        // The state changed; we check and update the status of all supported event
+        // types for current file description.
+        ecx.check_and_update_readiness(eventfd)?;
+
         // Tell userspace how many bytes we put into the buffer.
         return ecx.write_int(buf_place.layout.size.bytes(), dest);
     }
diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
index aa291639a6d..85c963774a1 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -3,6 +3,7 @@ use rustc_span::Symbol;
 use rustc_target::callconv::{Conv, FnAbi};
 
 use super::sync::EvalContextExt as _;
+use crate::helpers::check_min_arg_count;
 use crate::shims::unix::*;
 use crate::*;
 
@@ -67,6 +68,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let result = this.realpath(path, resolved_path)?;
                 this.write_scalar(result, dest)?;
             }
+            "ioctl" => {
+                // `ioctl` is variadic. The argument count is checked based on the first argument
+                // in `this.ioctl()`, so we do not use `check_shim` here.
+                this.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?;
+                let result = this.ioctl(args)?;
+                this.write_scalar(result, dest)?;
+            }
 
             // Environment related shims
             "_NSGetEnviron" => {
@@ -112,7 +120,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.check_no_isolation("`_NSGetExecutablePath`")?;
 
                 let buf_ptr = this.read_pointer(buf)?;
-                let bufsize = this.deref_pointer(bufsize)?;
+                let bufsize = this.deref_pointer_as(bufsize, this.machine.layouts.u32)?;
 
                 // Using the host current_exe is a bit off, but consistent with Linux
                 // (where stdlib reads /proc/self/exe).
@@ -234,4 +242,26 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         interp_ok(EmulateItemResult::NeedsReturn)
     }
+
+    fn ioctl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> {
+        let this = self.eval_context_mut();
+
+        let fioclex = this.eval_libc_u64("FIOCLEX");
+
+        let [fd_num, cmd] = check_min_arg_count("ioctl", args)?;
+        let fd_num = this.read_scalar(fd_num)?.to_i32()?;
+        let cmd = this.read_scalar(cmd)?.to_u64()?;
+
+        if cmd == fioclex {
+            // Since we don't support `exec`, this is a NOP. However, we want to
+            // return EBADF if the FD is invalid.
+            if this.machine.fds.is_fd_num(fd_num) {
+                interp_ok(Scalar::from_i32(0))
+            } else {
+                this.set_last_error_and_return_i32(LibcError("EBADF"))
+            }
+        } else {
+            throw_unsup_format!("ioctl: unsupported command {cmd:#x}");
+        }
+    }
 }
diff --git a/src/tools/miri/src/shims/unix/macos/sync.rs b/src/tools/miri/src/shims/unix/macos/sync.rs
index f66a57ae706..330c64f06a3 100644
--- a/src/tools/miri/src/shims/unix/macos/sync.rs
+++ b/src/tools/miri/src/shims/unix/macos/sync.rs
@@ -64,7 +64,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 None,
                 callback!(
                     @capture<'tcx> {}
-                    @unblock = |_this| {
+                    |_this, _unblock: UnblockKind| {
                         panic!("we shouldn't wake up ever")
                     }
                 ),
diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
index c99e8ae7c6e..f94783a3907 100644
--- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
@@ -3,6 +3,8 @@ use rustc_span::Symbol;
 use rustc_target::callconv::{Conv, FnAbi};
 
 use crate::shims::unix::foreign_items::EvalContextExt as _;
+use crate::shims::unix::linux_like::epoll::EvalContextExt as _;
+use crate::shims::unix::linux_like::eventfd::EvalContextExt as _;
 use crate::shims::unix::*;
 use crate::*;
 
@@ -21,6 +23,32 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx, EmulateItemResult> {
         let this = self.eval_context_mut();
         match link_name.as_str() {
+            // epoll, eventfd (NOT available on Solaris!)
+            "epoll_create1" => {
+                this.assert_target_os("illumos", "epoll_create1");
+                let [flag] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let result = this.epoll_create1(flag)?;
+                this.write_scalar(result, dest)?;
+            }
+            "epoll_ctl" => {
+                this.assert_target_os("illumos", "epoll_ctl");
+                let [epfd, op, fd, event] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let result = this.epoll_ctl(epfd, op, fd, event)?;
+                this.write_scalar(result, dest)?;
+            }
+            "epoll_wait" => {
+                this.assert_target_os("illumos", "epoll_wait");
+                let [epfd, events, maxevents, timeout] =
+                    this.check_shim(abi, Conv::C, link_name, args)?;
+                this.epoll_wait(epfd, events, maxevents, timeout, dest)?;
+            }
+            "eventfd" => {
+                this.assert_target_os("illumos", "eventfd");
+                let [val, flag] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let result = this.eventfd(val, flag)?;
+                this.write_scalar(result, dest)?;
+            }
+
             // Threading
             "pthread_setname_np" => {
                 let [thread, name] = this.check_shim(abi, Conv::C, link_name, args)?;
@@ -78,6 +106,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(result, dest)?;
             }
 
+            // Sockets and pipes
+            "__xnet_socketpair" => {
+                let [domain, type_, protocol, sv] =
+                    this.check_shim(abi, Conv::C, link_name, args)?;
+                let result = this.socketpair(domain, type_, protocol, sv)?;
+                this.write_scalar(result, dest)?;
+            }
+
             // Miscellaneous
             "___errno" => {
                 let [] = this.check_shim(abi, Conv::C, link_name, args)?;
diff --git a/src/tools/miri/src/shims/unix/unnamed_socket.rs b/src/tools/miri/src/shims/unix/unnamed_socket.rs
index 86ebe95762a..08515b815a9 100644
--- a/src/tools/miri/src/shims/unix/unnamed_socket.rs
+++ b/src/tools/miri/src/shims/unix/unnamed_socket.rs
@@ -31,7 +31,7 @@ struct AnonSocket {
     /// The `AnonSocket` file descriptor that is our "peer", and that holds the buffer we are
     /// writing to. This is a weak reference because the other side may be closed before us; all
     /// future writes will then trigger EPIPE.
-    peer_fd: OnceCell<WeakFileDescriptionRef>,
+    peer_fd: OnceCell<WeakFileDescriptionRef<AnonSocket>>,
     /// Indicates whether the peer has lost data when the file description is closed.
     /// This flag is set to `true` if the peer's `readbuf` is non-empty at the time
     /// of closure.
@@ -58,7 +58,7 @@ impl Buffer {
 }
 
 impl AnonSocket {
-    fn peer_fd(&self) -> &WeakFileDescriptionRef {
+    fn peer_fd(&self) -> &WeakFileDescriptionRef<AnonSocket> {
         self.peer_fd.get().unwrap()
     }
 }
@@ -69,7 +69,7 @@ impl FileDescription for AnonSocket {
     }
 
     fn close<'tcx>(
-        self: Box<Self>,
+        self,
         _communicate_allowed: bool,
         ecx: &mut MiriInterpCx<'tcx>,
     ) -> InterpResult<'tcx, io::Result<()>> {
@@ -78,80 +78,35 @@ impl FileDescription for AnonSocket {
             // notify the peer that data lost has happened in current file description.
             if let Some(readbuf) = &self.readbuf {
                 if !readbuf.borrow().buf.is_empty() {
-                    peer_fd.downcast::<AnonSocket>().unwrap().peer_lost_data.set(true);
+                    peer_fd.peer_lost_data.set(true);
                 }
             }
             // Notify peer fd that close has happened, since that can unblock reads and writes.
-            ecx.check_and_update_readiness(&peer_fd)?;
+            ecx.check_and_update_readiness(peer_fd)?;
         }
         interp_ok(Ok(()))
     }
 
     fn read<'tcx>(
-        &self,
-        self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         _communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
         dest: &MPlaceTy<'tcx>,
         ecx: &mut MiriInterpCx<'tcx>,
     ) -> InterpResult<'tcx> {
-        // Always succeed on read size 0.
-        if len == 0 {
-            return ecx.return_read_success(ptr, &[], 0, dest);
-        }
-
-        let Some(readbuf) = &self.readbuf else {
-            // FIXME: This should return EBADF, but there's no nice way to do that as there's no
-            // corresponding ErrorKind variant.
-            throw_unsup_format!("reading from the write end of a pipe");
-        };
-
-        if readbuf.borrow().buf.is_empty() && self.is_nonblock {
-            // Non-blocking socketpair with writer and empty buffer.
-            // https://linux.die.net/man/2/read
-            // EAGAIN or EWOULDBLOCK can be returned for socket,
-            // POSIX.1-2001 allows either error to be returned for this case.
-            // Since there is no ErrorKind for EAGAIN, WouldBlock is used.
-            return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
-        }
-        anonsocket_read(self_ref.downgrade(), len, ptr, dest.clone(), ecx)
+        anonsocket_read(self, len, ptr, dest, ecx)
     }
 
     fn write<'tcx>(
-        &self,
-        self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         _communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
         dest: &MPlaceTy<'tcx>,
         ecx: &mut MiriInterpCx<'tcx>,
     ) -> InterpResult<'tcx> {
-        // Always succeed on write size 0.
-        // ("If count is zero and fd refers to a file other than a regular file, the results are not specified.")
-        if len == 0 {
-            return ecx.return_write_success(0, dest);
-        }
-
-        // We are writing to our peer's readbuf.
-        let Some(peer_fd) = self.peer_fd().upgrade() else {
-            // If the upgrade from Weak to Rc fails, it indicates that all read ends have been
-            // closed.
-            return ecx.set_last_error_and_return(ErrorKind::BrokenPipe, dest);
-        };
-
-        let Some(writebuf) = &peer_fd.downcast::<AnonSocket>().unwrap().readbuf else {
-            // FIXME: This should return EBADF, but there's no nice way to do that as there's no
-            // corresponding ErrorKind variant.
-            throw_unsup_format!("writing to the reading end of a pipe");
-        };
-        let available_space =
-            MAX_SOCKETPAIR_BUFFER_CAPACITY.strict_sub(writebuf.borrow().buf.len());
-        if available_space == 0 && self.is_nonblock {
-            // Non-blocking socketpair with a full buffer.
-            return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
-        }
-        anonsocket_write(self_ref.downgrade(), ptr, len, dest.clone(), ecx)
+        anonsocket_write(self, ptr, len, dest, ecx)
     }
 
     fn as_unix(&self) -> &dyn UnixFileDescription {
@@ -161,50 +116,64 @@ impl FileDescription for AnonSocket {
 
 /// Write to AnonSocket based on the space available and return the written byte size.
 fn anonsocket_write<'tcx>(
-    weak_self_ref: WeakFileDescriptionRef,
+    self_ref: FileDescriptionRef<AnonSocket>,
     ptr: Pointer,
     len: usize,
-    dest: MPlaceTy<'tcx>,
+    dest: &MPlaceTy<'tcx>,
     ecx: &mut MiriInterpCx<'tcx>,
 ) -> InterpResult<'tcx> {
-    let Some(self_ref) = weak_self_ref.upgrade() else {
-        // FIXME:  We should raise a deadlock error if the self_ref upgrade failed.
-        throw_unsup_format!("This will be a deadlock error in future")
-    };
-    let self_anonsocket = self_ref.downcast::<AnonSocket>().unwrap();
-    let Some(peer_fd) = self_anonsocket.peer_fd().upgrade() else {
+    // Always succeed on write size 0.
+    // ("If count is zero and fd refers to a file other than a regular file, the results are not specified.")
+    if len == 0 {
+        return ecx.return_write_success(0, dest);
+    }
+
+    // We are writing to our peer's readbuf.
+    let Some(peer_fd) = self_ref.peer_fd().upgrade() else {
         // If the upgrade from Weak to Rc fails, it indicates that all read ends have been
-        // closed.
-        return ecx.set_last_error_and_return(ErrorKind::BrokenPipe, &dest);
+        // closed. It is an error to write even if there would be space.
+        return ecx.set_last_error_and_return(ErrorKind::BrokenPipe, dest);
     };
-    let Some(writebuf) = &peer_fd.downcast::<AnonSocket>().unwrap().readbuf else {
-        // FIXME: This should return EBADF, but there's no nice way to do that as there's no
-        // corresponding ErrorKind variant.
-        throw_unsup_format!("writing to the reading end of a pipe")
+
+    let Some(writebuf) = &peer_fd.readbuf else {
+        // Writing to the read end of a pipe.
+        return ecx.set_last_error_and_return(IoError::LibcError("EBADF"), dest);
     };
 
+    // Let's see if we can write.
     let available_space = MAX_SOCKETPAIR_BUFFER_CAPACITY.strict_sub(writebuf.borrow().buf.len());
-
     if available_space == 0 {
-        // Blocking socketpair with a full buffer.
-        let dest = dest.clone();
-        self_anonsocket.blocked_write_tid.borrow_mut().push(ecx.active_thread());
-        ecx.block_thread(
-            BlockReason::UnnamedSocket,
-            None,
-            callback!(
-                @capture<'tcx> {
-                    weak_self_ref: WeakFileDescriptionRef,
-                    ptr: Pointer,
-                    len: usize,
-                    dest: MPlaceTy<'tcx>,
-                }
-                @unblock = |this| {
-                    anonsocket_write(weak_self_ref, ptr, len, dest, this)
-                }
-            ),
-        );
+        if self_ref.is_nonblock {
+            // Non-blocking socketpair with a full buffer.
+            return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
+        } else {
+            self_ref.blocked_write_tid.borrow_mut().push(ecx.active_thread());
+            // Blocking socketpair with a full buffer.
+            // Block the current thread; only keep a weak ref for this.
+            let weak_self_ref = FileDescriptionRef::downgrade(&self_ref);
+            let dest = dest.clone();
+            ecx.block_thread(
+                BlockReason::UnnamedSocket,
+                None,
+                callback!(
+                    @capture<'tcx> {
+                        weak_self_ref: WeakFileDescriptionRef<AnonSocket>,
+                        ptr: Pointer,
+                        len: usize,
+                        dest: MPlaceTy<'tcx>,
+                    }
+                    |this, unblock: UnblockKind| {
+                        assert_eq!(unblock, UnblockKind::Ready);
+                        // If we got unblocked, then our peer successfully upgraded its weak
+                        // ref to us. That means we can also upgrade our weak ref.
+                        let self_ref = weak_self_ref.upgrade().unwrap();
+                        anonsocket_write(self_ref, ptr, len, &dest, this)
+                    }
+                ),
+            );
+        }
     } else {
+        // There is space to write!
         let mut writebuf = writebuf.borrow_mut();
         // Remember this clock so `read` can synchronize with us.
         ecx.release_clock(|clock| {
@@ -218,68 +187,80 @@ fn anonsocket_write<'tcx>(
         // Need to stop accessing peer_fd so that it can be notified.
         drop(writebuf);
 
-        // Notification should be provided for peer fd as it became readable.
-        // The kernel does this even if the fd was already readable before, so we follow suit.
-        ecx.check_and_update_readiness(&peer_fd)?;
-        let peer_anonsocket = peer_fd.downcast::<AnonSocket>().unwrap();
         // Unblock all threads that are currently blocked on peer_fd's read.
-        let waiting_threads = std::mem::take(&mut *peer_anonsocket.blocked_read_tid.borrow_mut());
+        let waiting_threads = std::mem::take(&mut *peer_fd.blocked_read_tid.borrow_mut());
         // FIXME: We can randomize the order of unblocking.
         for thread_id in waiting_threads {
             ecx.unblock_thread(thread_id, BlockReason::UnnamedSocket)?;
         }
+        // Notification should be provided for peer fd as it became readable.
+        // The kernel does this even if the fd was already readable before, so we follow suit.
+        ecx.check_and_update_readiness(peer_fd)?;
 
-        return ecx.return_write_success(actual_write_size, &dest);
+        return ecx.return_write_success(actual_write_size, dest);
     }
     interp_ok(())
 }
 
 /// Read from AnonSocket and return the number of bytes read.
 fn anonsocket_read<'tcx>(
-    weak_self_ref: WeakFileDescriptionRef,
+    self_ref: FileDescriptionRef<AnonSocket>,
     len: usize,
     ptr: Pointer,
-    dest: MPlaceTy<'tcx>,
+    dest: &MPlaceTy<'tcx>,
     ecx: &mut MiriInterpCx<'tcx>,
 ) -> InterpResult<'tcx> {
-    let Some(self_ref) = weak_self_ref.upgrade() else {
-        // FIXME:  We should raise a deadlock error if the self_ref upgrade failed.
-        throw_unsup_format!("This will be a deadlock error in future")
-    };
-    let self_anonsocket = self_ref.downcast::<AnonSocket>().unwrap();
+    // Always succeed on read size 0.
+    if len == 0 {
+        return ecx.return_read_success(ptr, &[], 0, dest);
+    }
 
-    let Some(readbuf) = &self_anonsocket.readbuf else {
+    let Some(readbuf) = &self_ref.readbuf else {
         // FIXME: This should return EBADF, but there's no nice way to do that as there's no
         // corresponding ErrorKind variant.
         throw_unsup_format!("reading from the write end of a pipe")
     };
 
     if readbuf.borrow_mut().buf.is_empty() {
-        if self_anonsocket.peer_fd().upgrade().is_none() {
+        if self_ref.peer_fd().upgrade().is_none() {
             // Socketpair with no peer and empty buffer.
             // 0 bytes successfully read indicates end-of-file.
-            return ecx.return_read_success(ptr, &[], 0, &dest);
+            return ecx.return_read_success(ptr, &[], 0, dest);
+        } else if self_ref.is_nonblock {
+            // Non-blocking socketpair with writer and empty buffer.
+            // https://linux.die.net/man/2/read
+            // EAGAIN or EWOULDBLOCK can be returned for socket,
+            // POSIX.1-2001 allows either error to be returned for this case.
+            // Since there is no ErrorKind for EAGAIN, WouldBlock is used.
+            return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
         } else {
+            self_ref.blocked_read_tid.borrow_mut().push(ecx.active_thread());
             // Blocking socketpair with writer and empty buffer.
-            let weak_self_ref = weak_self_ref.clone();
-            self_anonsocket.blocked_read_tid.borrow_mut().push(ecx.active_thread());
+            // Block the current thread; only keep a weak ref for this.
+            let weak_self_ref = FileDescriptionRef::downgrade(&self_ref);
+            let dest = dest.clone();
             ecx.block_thread(
                 BlockReason::UnnamedSocket,
                 None,
                 callback!(
                     @capture<'tcx> {
-                        weak_self_ref: WeakFileDescriptionRef,
+                        weak_self_ref: WeakFileDescriptionRef<AnonSocket>,
                         len: usize,
                         ptr: Pointer,
                         dest: MPlaceTy<'tcx>,
                     }
-                    @unblock = |this| {
-                        anonsocket_read(weak_self_ref, len, ptr, dest, this)
+                    |this, unblock: UnblockKind| {
+                        assert_eq!(unblock, UnblockKind::Ready);
+                        // If we got unblocked, then our peer successfully upgraded its weak
+                        // ref to us. That means we can also upgrade our weak ref.
+                        let self_ref = weak_self_ref.upgrade().unwrap();
+                        anonsocket_read(self_ref, len, ptr, &dest, this)
                     }
                 ),
             );
         }
     } else {
+        // There's data to be read!
         let mut bytes = vec![0; len];
         let mut readbuf = readbuf.borrow_mut();
         // Synchronize with all previous writes to this buffer.
@@ -301,19 +282,18 @@ fn anonsocket_read<'tcx>(
         // don't know what that *certain number* is, we will provide a notification every time
         // a read is successful. This might result in our epoll emulation providing more
         // notifications than the real system.
-        if let Some(peer_fd) = self_anonsocket.peer_fd().upgrade() {
-            ecx.check_and_update_readiness(&peer_fd)?;
-            let peer_anonsocket = peer_fd.downcast::<AnonSocket>().unwrap();
+        if let Some(peer_fd) = self_ref.peer_fd().upgrade() {
             // Unblock all threads that are currently blocked on peer_fd's write.
-            let waiting_threads =
-                std::mem::take(&mut *peer_anonsocket.blocked_write_tid.borrow_mut());
+            let waiting_threads = std::mem::take(&mut *peer_fd.blocked_write_tid.borrow_mut());
             // FIXME: We can randomize the order of unblocking.
             for thread_id in waiting_threads {
                 ecx.unblock_thread(thread_id, BlockReason::UnnamedSocket)?;
             }
+            // Notify epoll waiters.
+            ecx.check_and_update_readiness(peer_fd)?;
         };
 
-        return ecx.return_read_success(ptr, &bytes, actual_read_size, &dest);
+        return ecx.return_read_success(ptr, &bytes, actual_read_size, dest);
     }
     interp_ok(())
 }
@@ -337,7 +317,7 @@ impl UnixFileDescription for AnonSocket {
 
         // Check if is writable.
         if let Some(peer_fd) = self.peer_fd().upgrade() {
-            if let Some(writebuf) = &peer_fd.downcast::<AnonSocket>().unwrap().readbuf {
+            if let Some(writebuf) = &peer_fd.readbuf {
                 let data_size = writebuf.borrow().buf.len();
                 let available_space = MAX_SOCKETPAIR_BUFFER_CAPACITY.strict_sub(data_size);
                 if available_space != 0 {
@@ -443,8 +423,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         });
 
         // Make the file descriptions point to each other.
-        fd0.downcast::<AnonSocket>().unwrap().peer_fd.set(fd1.downgrade()).unwrap();
-        fd1.downcast::<AnonSocket>().unwrap().peer_fd.set(fd0.downgrade()).unwrap();
+        fd0.peer_fd.set(FileDescriptionRef::downgrade(&fd1)).unwrap();
+        fd1.peer_fd.set(FileDescriptionRef::downgrade(&fd0)).unwrap();
 
         // Insert the file description to the fd table, generating the file descriptors.
         let sv0 = fds.insert(fd0);
@@ -511,8 +491,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         });
 
         // Make the file descriptions point to each other.
-        fd0.downcast::<AnonSocket>().unwrap().peer_fd.set(fd1.downgrade()).unwrap();
-        fd1.downcast::<AnonSocket>().unwrap().peer_fd.set(fd0.downgrade()).unwrap();
+        fd0.peer_fd.set(FileDescriptionRef::downgrade(&fd1)).unwrap();
+        fd1.peer_fd.set(FileDescriptionRef::downgrade(&fd0)).unwrap();
 
         // Insert the file description to the fd table, generating the file descriptors.
         let pipefd0 = fds.insert(fd0);
diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs
index 3d872b65a63..c4eb11fbd3f 100644
--- a/src/tools/miri/src/shims/windows/handle.rs
+++ b/src/tools/miri/src/shims/windows/handle.rs
@@ -97,7 +97,7 @@ impl Handle {
 
         // packs the data into the lower `data_size` bits
         // and packs the discriminant right above the data
-        discriminant << data_size | data
+        (discriminant << data_size) | data
     }
 
     fn new(discriminant: u32, data: u32) -> Option<Self> {
diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs
index a394e0430bc..4001201bf67 100644
--- a/src/tools/miri/src/shims/windows/sync.rs
+++ b/src/tools/miri/src/shims/windows/sync.rs
@@ -111,7 +111,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     pending_place: MPlaceTy<'tcx>,
                     dest: MPlaceTy<'tcx>,
                 }
-                @unblock = |this| {
+                |this, unblock: UnblockKind| {
+                    assert_eq!(unblock, UnblockKind::Ready);
                     let ret = this.init_once_try_begin(id, &pending_place, &dest)?;
                     assert!(ret, "we were woken up but init_once_try_begin still failed");
                     interp_ok(())
diff --git a/src/tools/miri/test-cargo-miri/no-std-smoke/src/main.rs b/src/tools/miri/test-cargo-miri/no-std-smoke/src/main.rs
index 3a207b7d50a..d9f1b27bf55 100644
--- a/src/tools/miri/test-cargo-miri/no-std-smoke/src/main.rs
+++ b/src/tools/miri/test-cargo-miri/no-std-smoke/src/main.rs
@@ -1,6 +1,5 @@
 // Copied from tests/pass/no-std.rs
 
-#![feature(start)]
 #![no_std]
 
 // Plumbing to let us use `writeln!` to host stdout:
@@ -22,8 +21,8 @@ impl Write for Host {
     }
 }
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+fn miri_start(_: isize, _: *const *const u8) -> isize {
     writeln!(Host, "hello, world!").unwrap();
     0
 }
diff --git a/src/tools/miri/tests/fail-dep/libc/affinity.rs b/src/tools/miri/tests/fail-dep/libc/affinity.rs
index 09f096e46f1..3acbd83d0e5 100644
--- a/src/tools/miri/tests/fail-dep/libc/affinity.rs
+++ b/src/tools/miri/tests/fail-dep/libc/affinity.rs
@@ -1,5 +1,4 @@
-//@ignore-target: windows # only very limited libc on Windows
-//@ignore-target: apple # `sched_setaffinity` is not supported on macOS
+//@only-target: linux # these are Linux-specific APIs
 //@compile-flags: -Zmiri-disable-isolation -Zmiri-num-cpus=4
 
 fn main() {
diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs
index 81a96103db4..0d893663fd6 100644
--- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs
+++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs
@@ -1,4 +1,4 @@
-//@only-target: linux
+//@only-target: linux android illumos
 //~^ERROR: deadlocked
 //~^^ERROR: deadlocked
 //@compile-flags: -Zmiri-preemption-rate=0
diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs
index 7a2a6f4eb1a..9fed47c17d4 100644
--- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs
+++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs
@@ -1,4 +1,4 @@
-//@only-target: linux
+//@only-target: linux android illumos
 //~^ERROR: deadlocked
 //~^^ERROR: deadlocked
 //@compile-flags: -Zmiri-preemption-rate=0
diff --git a/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs b/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs
index 7bef687e339..45f6bf6da09 100644
--- a/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs
+++ b/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs
@@ -2,7 +2,7 @@
 //! and we only read one of them, we do not synchronize with the other events
 //! and therefore still report a data race for things that need to see the second event
 //! to be considered synchronized.
-//@only-target: linux android
+//@only-target: linux android illumos
 // ensure deterministic schedule
 //@compile-flags: -Zmiri-preemption-rate=0
 
diff --git a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs
index 1c6c2f70c1d..059b24cb8c0 100644
--- a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs
+++ b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs
@@ -1,7 +1,7 @@
 //@compile-flags: -Zmiri-preemption-rate=0
 //~^ERROR: deadlocked
 //~^^ERROR: deadlocked
-//@only-target: linux
+//@only-target: linux android illumos
 //@error-in-other-file: deadlock
 
 use std::convert::TryInto;
diff --git a/src/tools/miri/tests/fail-dep/libc/libc_epoll_unsupported_fd.rs b/src/tools/miri/tests/fail-dep/libc/libc_epoll_unsupported_fd.rs
index 03d4b2d6633..59cf0fc2ba0 100644
--- a/src/tools/miri/tests/fail-dep/libc/libc_epoll_unsupported_fd.rs
+++ b/src/tools/miri/tests/fail-dep/libc/libc_epoll_unsupported_fd.rs
@@ -1,4 +1,4 @@
-//@only-target: linux
+//@only-target: linux android illumos
 
 // This is a test for registering unsupported fd with epoll.
 // Register epoll fd with epoll is allowed in real system, but we do not support this.
diff --git a/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs b/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs
index 8b34ff4ac2e..a1d8fd663f8 100644
--- a/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs
+++ b/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs
@@ -1,9 +1,8 @@
-//@ignore-target: windows # No `memrchr` on Windows
-//@ignore-target: apple # No `memrchr` on some apple targets
+//@only-target: linux # `memrchr` is a GNU extension
 
 use std::ptr;
 
-// null is explicitly called out as UB in the C docs.
+// null is explicitly called out as UB in the C docs for `memchr`.
 fn main() {
     unsafe {
         libc::memrchr(ptr::null(), 0, 0); //~ERROR: null pointer
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs
new file mode 100644
index 00000000000..8413e118819
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs
@@ -0,0 +1,37 @@
+//! This is a regression test for <https://github.com/rust-lang/miri/issues/3947>: we had some
+//! faulty logic around `release_clock` that led to this code not reporting a data race.
+//~^^ERROR: deadlock
+//@ignore-target: windows # no libc socketpair on Windows
+//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-rate=0
+//@error-in-other-file: deadlock
+use std::thread;
+
+fn main() {
+    let mut fds = [-1, -1];
+    let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) };
+    assert_eq!(res, 0);
+
+    let thread1 = thread::spawn(move || {
+        let mut buf: [u8; 1] = [0; 1];
+        let _res: i32 = unsafe {
+            libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) //~ERROR: deadlock
+                .try_into()
+                .unwrap()
+        };
+    });
+    let thread2 = thread::spawn(move || {
+        // Close the FD that the other thread is blocked on.
+        unsafe { libc::close(fds[1]) };
+    });
+
+    // Run the other threads.
+    thread::yield_now();
+
+    // When they are both done, continue here.
+    let data = "a".as_bytes().as_ptr();
+    let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 1) };
+    assert_eq!(res, -1);
+
+    thread1.join().unwrap();
+    thread2.join().unwrap();
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr
new file mode 100644
index 00000000000..fe196f5d7d7
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr
@@ -0,0 +1,35 @@
+error: deadlock: the evaluated program deadlocked
+  --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   |
+LL |         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
+   |                                                                  ^ the evaluated program deadlocked
+   |
+   = note: BACKTRACE:
+   = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
+   = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
+note: inside `main`
+  --> tests/fail-dep/libc/socketpair-close-while-blocked.rs:LL:CC
+   |
+LL |     thread1.join().unwrap();
+   |     ^^^^^^^^^^^^^^
+
+error: deadlock: the evaluated program deadlocked
+  --> tests/fail-dep/libc/socketpair-close-while-blocked.rs:LL:CC
+   |
+LL |             libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t)
+   |                                                                                  ^ the evaluated program deadlocked
+   |
+   = note: BACKTRACE on thread `unnamed-ID`:
+   = note: inside closure at tests/fail-dep/libc/socketpair-close-while-blocked.rs:LL:CC
+
+error: deadlock: the evaluated program deadlocked
+   |
+   = note: the evaluated program deadlocked
+   = note: (no span available)
+   = note: BACKTRACE on thread `unnamed-ID`:
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.rs b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.rs
index babdb73f093..8d41002735c 100644
--- a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.rs
+++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.rs
@@ -1,8 +1,9 @@
 //@compile-flags: -Cpanic=abort
-#![feature(start, core_intrinsics)]
+#![feature(core_intrinsics)]
 #![feature(alloc_error_handler)]
 #![feature(allocator_api)]
 #![no_std]
+#![no_main]
 
 extern crate alloc;
 
@@ -43,7 +44,7 @@ mod plumbing {
     static GLOBAL: NoAlloc = NoAlloc;
 }
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
     handle_alloc_error(Layout::for_value(&0));
 }
diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr
index d12e119bce3..1a9e7574339 100644
--- a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr
+++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr
@@ -16,7 +16,7 @@ LL | fn alloc_error_handler(layout: Layout) -> ! {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: inside `alloc::alloc::handle_alloc_error::rt_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC
    = note: inside `alloc::alloc::handle_alloc_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-note: inside `start`
+note: inside `miri_start`
   --> tests/fail/alloc/alloc_error_handler_custom.rs:LL:CC
    |
 LL |     handle_alloc_error(Layout::for_value(&0));
diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.rs b/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.rs
index 18a8a61f22f..f73f8e3e7e1 100644
--- a/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.rs
+++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.rs
@@ -1,8 +1,9 @@
 //@compile-flags: -Cpanic=abort
-#![feature(start, core_intrinsics)]
+#![feature(core_intrinsics)]
 #![feature(alloc_error_handler)]
 #![feature(allocator_api)]
 #![no_std]
+#![no_main]
 
 extern crate alloc;
 
@@ -41,7 +42,7 @@ mod plumbing {
     static GLOBAL: NoAlloc = NoAlloc;
 }
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
     handle_alloc_error(Layout::for_value(&0));
 }
diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr
index f495d65a8b0..6b4266b9a8b 100644
--- a/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr
+++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr
@@ -12,7 +12,7 @@ LL |     core::intrinsics::abort();
    = note: inside `alloc::alloc::__alloc_error_handler::__rdl_oom` at RUSTLIB/alloc/src/alloc.rs:LL:CC
    = note: inside `alloc::alloc::handle_alloc_error::rt_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC
    = note: inside `alloc::alloc::handle_alloc_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-note: inside `start`
+note: inside `miri_start`
   --> tests/fail/alloc/alloc_error_handler_no_std.rs:LL:CC
    |
 LL |     handle_alloc_error(Layout::for_value(&0));
diff --git a/src/tools/miri/tests/fail/alloc/no_global_allocator.rs b/src/tools/miri/tests/fail/alloc/no_global_allocator.rs
index 0952b2c46ba..f76aebaa3e3 100644
--- a/src/tools/miri/tests/fail/alloc/no_global_allocator.rs
+++ b/src/tools/miri/tests/fail/alloc/no_global_allocator.rs
@@ -2,15 +2,15 @@
 //@normalize-stderr-test: "OS `.*`" -> "$$OS"
 // Make sure we pretend the allocation symbols don't exist when there is no allocator
 
-#![feature(start)]
 #![no_std]
+#![no_main]
 
 extern "Rust" {
     fn __rust_alloc(size: usize, align: usize) -> *mut u8;
 }
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
     unsafe {
         __rust_alloc(1, 1); //~ERROR: unsupported operation: can't call foreign function `__rust_alloc`
     }
diff --git a/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr b/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr
index e08a747f7fa..541af64b894 100644
--- a/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr
+++ b/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr
@@ -7,7 +7,7 @@ LL |         __rust_alloc(1, 1);
    = help: if this is a basic API commonly used on this target, please report an issue with Miri
    = help: however, note that Miri does not aim to support every FFI function out there; for instance, we will not support APIs for things such as GUIs, scripting languages, or databases
    = note: BACKTRACE:
-   = note: inside `start` at tests/fail/alloc/no_global_allocator.rs:LL:CC
+   = note: inside `miri_start` at tests/fail/alloc/no_global_allocator.rs:LL:CC
 
 error: aborting due to 1 previous error
 
diff --git a/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs b/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs
index 9c73bdc17be..791ffa7343d 100644
--- a/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs
+++ b/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
-}
+#[rustc_intrinsic]
+unsafe fn copy_nonoverlapping<T>(_src: *const T, _dst: *mut T, _count: usize);
 
 fn main() {
     let mut data = [0u8; 16];
diff --git a/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs b/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs
index 281217f06f5..9a82c69fba8 100644
--- a/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs
+++ b/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
-}
+#[rustc_intrinsic]
+unsafe fn copy_nonoverlapping<T>(_src: *const T, _dst: *mut T, _count: usize);
 
 fn main() {
     let mut data = [0u16; 8];
diff --git a/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.rs b/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.rs
index 0b34afc6090..e42811d9e13 100644
--- a/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.rs
+++ b/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 mod rusti {
-    extern "rust-intrinsic" {
-        pub fn ctlz_nonzero<T>(x: T) -> u32;
-    }
+    #[rustc_intrinsic]
+    pub unsafe fn ctlz_nonzero<T>(_x: T) -> u32;
 }
 
 pub fn main() {
diff --git a/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.rs b/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.rs
index e220411f585..a1f7a5881d4 100644
--- a/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.rs
+++ b/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.rs
@@ -1,9 +1,9 @@
+
 #![feature(intrinsics)]
 
 mod rusti {
-    extern "rust-intrinsic" {
-        pub fn cttz_nonzero<T>(x: T) -> u32;
-    }
+    #[rustc_intrinsic]
+    pub unsafe fn cttz_nonzero<T>(_x: T) -> u32;
 }
 
 pub fn main() {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.rs
index a57845426d5..d75046ff360 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
-}
+#[rustc_intrinsic]
+unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.rs
index d383fc5b50a..8d343cdc1bd 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
-}
+#[rustc_intrinsic]
+unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.rs
index a39a5066b6f..737a6fbafe0 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
-}
+#[rustc_intrinsic]
+unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.rs
index 71436eb3ba8..a1c307efc93 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.rs
@@ -1,9 +1,9 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
-}
+#[rustc_intrinsic]
+unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
+
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.rs
index 98ba964e47c..4bb5ded1033 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
-}
+#[rustc_intrinsic]
+unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.rs
index 424b8fd965e..6b42ae56ece 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
-}
+#[rustc_intrinsic]
+unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.rs
index 5c50926c4df..81019a1c608 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
-}
+#[rustc_intrinsic]
+unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.rs
index e0abd19d03f..24896bcae51 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
-}
+#[rustc_intrinsic]
+unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.rs
index f5f842e58ec..fbb67d28fed 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
-}
+#[rustc_intrinsic]
+unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.rs
index 244c25b31cb..284b429230d 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.rs
@@ -1,9 +1,9 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
-}
+#[rustc_intrinsic]
+unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
+
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.rs
index f7a663d12a5..2770dea4406 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
-}
+#[rustc_intrinsic]
+unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.rs
index 171cbcc5934..1272566c07c 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
-}
+#[rustc_intrinsic]
+unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.rs
index 40b67e173b9..a1165794982 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
-}
+#[rustc_intrinsic]
+unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.rs
index e785123c4ca..0e68f4eaff7 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
-}
+#[rustc_intrinsic]
+unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.rs
index 4bf31d8ac02..ad3ac16dc6f 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
-}
+#[rustc_intrinsic]
+unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.rs
index 9775a56724b..1addb9fb1d7 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
-}
+#[rustc_intrinsic]
+unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.rs
index 53ff06e1e46..a04c29c37da 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
-}
+#[rustc_intrinsic]
+unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.rs
index 44356ff1771..32bdcd07073 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
-}
+#[rustc_intrinsic]
+unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.rs
index 66f5be96bfd..861af44a66f 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
-}
+#[rustc_intrinsic]
+unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.rs
index 18b380e8575..3b3e208f32f 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
-}
+#[rustc_intrinsic]
+unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.rs
index 2a23b1dc8a4..81ca766de47 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
-}
+#[rustc_intrinsic]
+unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.rs
index 7fc3effda5d..2b437f38552 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
-}
+#[rustc_intrinsic]
+unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.rs
index 2a8f9c36642..94ee572f4d0 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.rs
@@ -1,9 +1,8 @@
 #![feature(intrinsics)]
 
 // Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
-}
+#[rustc_intrinsic]
+unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/panic/no_std.rs b/src/tools/miri/tests/fail/panic/no_std.rs
index 4d32b6d7461..cd8a3251fef 100644
--- a/src/tools/miri/tests/fail/panic/no_std.rs
+++ b/src/tools/miri/tests/fail/panic/no_std.rs
@@ -1,14 +1,15 @@
 //@compile-flags: -Cpanic=abort
-#![feature(start, core_intrinsics)]
+#![feature(core_intrinsics)]
 #![no_std]
+#![no_main]
 
 use core::fmt::Write;
 
 #[path = "../../utils/mod.no_std.rs"]
 mod utils;
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
     panic!("blarg I am dead")
 }
 
diff --git a/src/tools/miri/tests/fail/panic/no_std.stderr b/src/tools/miri/tests/fail/panic/no_std.stderr
index c1cd53e310f..d54f2a58776 100644
--- a/src/tools/miri/tests/fail/panic/no_std.stderr
+++ b/src/tools/miri/tests/fail/panic/no_std.stderr
@@ -8,7 +8,7 @@ LL |     core::intrinsics::abort();
    |
    = note: BACKTRACE:
    = note: inside `panic_handler` at tests/fail/panic/no_std.rs:LL:CC
-note: inside `start`
+note: inside `miri_start`
   --> tests/fail/panic/no_std.rs:LL:CC
    |
 LL |     panic!("blarg I am dead")
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs
index 3c4311efc4c..400e3ca3d7d 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs
@@ -1,5 +1,4 @@
-//@ignore-target: windows # only very limited libc on Windows
-//@ignore-target: apple # `sched_{g, s}etaffinity` are not supported on macOS
+//@only-target: linux # these are Linux-specific APIs
 //@compile-flags: -Zmiri-disable-isolation -Zmiri-num-cpus=4
 #![feature(io_error_more)]
 #![feature(pointer_is_aligned_to)]
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs
index e3c42b2701c..825e1355848 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs
@@ -1,4 +1,4 @@
-//@only-target: linux android
+//@only-target: linux android illumos
 // test_epoll_block_then_unblock and test_epoll_race depend on a deterministic schedule.
 //@compile-flags: -Zmiri-preemption-rate=0
 
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs b/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs
index 111e639c864..23e2122ee50 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs
@@ -1,4 +1,4 @@
-//@only-target: linux android
+//@only-target: linux android illumos
 
 use std::convert::TryInto;
 
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs
index 2e453215ec9..30e1bbb8fa1 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs
@@ -1,4 +1,4 @@
-//@only-target: linux android
+//@only-target: linux android illumos
 // test_race, test_blocking_read and test_blocking_write depend on a deterministic schedule.
 //@compile-flags: -Zmiri-preemption-rate=0
 
@@ -10,7 +10,10 @@ use std::thread;
 fn main() {
     test_read_write();
     test_race();
+
+    #[cfg(not(target_os = "illumos"))]
     test_syscall();
+
     test_blocking_read();
     test_blocking_write();
     test_two_threads_blocked_on_eventfd();
@@ -115,6 +118,8 @@ fn test_race() {
 }
 
 // This is a test for calling eventfd2 through a syscall.
+// Illumos supports eventfd, but it has no entry to call it through syscall.
+#[cfg(not(target_os = "illumos"))]
 fn test_syscall() {
     let initval = 0 as libc::c_uint;
     let flags = (libc::EFD_CLOEXEC | libc::EFD_NONBLOCK) as libc::c_int;
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
index f85abe2cc43..129b18d8e59 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
@@ -38,6 +38,8 @@ fn main() {
     test_isatty();
     test_read_and_uninit();
     test_nofollow_not_symlink();
+    #[cfg(target_os = "macos")]
+    test_ioctl();
 }
 
 fn test_file_open_unix_allow_two_args() {
@@ -431,3 +433,21 @@ fn test_nofollow_not_symlink() {
     let ret = unsafe { libc::open(cpath.as_ptr(), libc::O_NOFOLLOW | libc::O_CLOEXEC) };
     assert!(ret >= 0);
 }
+
+#[cfg(target_os = "macos")]
+fn test_ioctl() {
+    let path = utils::prepare_with_content("miri_test_libc_ioctl.txt", &[]);
+
+    let mut name = path.into_os_string();
+    name.push("\0");
+    let name_ptr = name.as_bytes().as_ptr().cast::<libc::c_char>();
+    unsafe {
+        // 100 surely is an invalid FD.
+        assert_eq!(libc::ioctl(100, libc::FIOCLEX), -1);
+        let errno = std::io::Error::last_os_error().raw_os_error().unwrap();
+        assert_eq!(errno, libc::EBADF);
+
+        let fd = libc::open(name_ptr, libc::O_RDONLY);
+        assert_eq!(libc::ioctl(fd, libc::FIOCLEX), 0);
+    }
+}
diff --git a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs
index cf634bc6890..6ac71b5ad1e 100644
--- a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs
+++ b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs
@@ -29,12 +29,13 @@ fn main() {
 
     fn set_thread_name(name: &CStr) -> i32 {
         cfg_if::cfg_if! {
-            if #[cfg(any(target_os = "linux", target_os = "illumos", target_os = "solaris"))] {
+            if #[cfg(any(
+                target_os = "linux",
+                target_os = "freebsd",
+                target_os = "illumos",
+                target_os = "solaris"
+            ))] {
                 unsafe { libc::pthread_setname_np(libc::pthread_self(), name.as_ptr().cast()) }
-            } else if #[cfg(target_os = "freebsd")] {
-                // pthread_set_name_np does not return anything
-                unsafe { libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr().cast()) };
-                0
             } else if #[cfg(target_os = "macos")] {
                 unsafe { libc::pthread_setname_np(name.as_ptr().cast()) }
             } else {
@@ -47,6 +48,7 @@ fn main() {
         cfg_if::cfg_if! {
             if #[cfg(any(
                 target_os = "linux",
+                target_os = "freebsd",
                 target_os = "illumos",
                 target_os = "solaris",
                 target_os = "macos"
@@ -54,12 +56,6 @@ fn main() {
                 unsafe {
                     libc::pthread_getname_np(libc::pthread_self(), name.as_mut_ptr().cast(), name.len())
                 }
-            } else if #[cfg(target_os = "freebsd")] {
-                // pthread_get_name_np does not return anything
-                unsafe {
-                    libc::pthread_get_name_np(libc::pthread_self(), name.as_mut_ptr().cast(), name.len())
-                };
-                0
             } else {
                 compile_error!("get_thread_name not supported for this OS")
             }
@@ -201,27 +197,25 @@ fn main() {
         .unwrap();
 
     // Now set the name for a non-existing thread and verify error codes.
-    // (FreeBSD doesn't return an error code.)
-    #[cfg(not(target_os = "freebsd"))]
-    {
-        let invalid_thread = 0xdeadbeef;
-        let error = {
-            cfg_if::cfg_if! {
-                if #[cfg(target_os = "linux")] {
-                    libc::ENOENT
-                } else {
-                    libc::ESRCH
-                }
+    let invalid_thread = 0xdeadbeef;
+    let error = {
+        cfg_if::cfg_if! {
+            if #[cfg(target_os = "linux")] {
+                libc::ENOENT
+            } else {
+                libc::ESRCH
             }
-        };
-        #[cfg(not(target_os = "macos"))]
-        {
-            // macOS has no `setname` function accepting a thread id as the first argument.
-            let res = unsafe { libc::pthread_setname_np(invalid_thread, [0].as_ptr()) };
-            assert_eq!(res, error);
         }
-        let mut buf = [0; 64];
-        let res = unsafe { libc::pthread_getname_np(invalid_thread, buf.as_mut_ptr(), buf.len()) };
+    };
+
+    #[cfg(not(target_os = "macos"))]
+    {
+        // macOS has no `setname` function accepting a thread id as the first argument.
+        let res = unsafe { libc::pthread_setname_np(invalid_thread, [0].as_ptr()) };
         assert_eq!(res, error);
     }
+
+    let mut buf = [0; 64];
+    let res = unsafe { libc::pthread_getname_np(invalid_thread, buf.as_mut_ptr(), buf.len()) };
+    assert_eq!(res, error);
 }
diff --git a/src/tools/miri/tests/pass/alloc-access-tracking.rs b/src/tools/miri/tests/pass/alloc-access-tracking.rs
index 50e217918b0..c47063bef03 100644
--- a/src/tools/miri/tests/pass/alloc-access-tracking.rs
+++ b/src/tools/miri/tests/pass/alloc-access-tracking.rs
@@ -1,5 +1,5 @@
-#![feature(start)]
 #![no_std]
+#![no_main]
 //@compile-flags: -Zmiri-track-alloc-id=21 -Zmiri-track-alloc-accesses -Cpanic=abort
 //@normalize-stderr-test: "id 21" -> "id $$ALLOC"
 //@only-target: linux # alloc IDs differ between OSes (due to extern static allocations)
@@ -9,8 +9,8 @@ extern "Rust" {
     fn miri_dealloc(ptr: *mut u8, size: usize, align: usize);
 }
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
     unsafe {
         let ptr = miri_alloc(123, 1);
         *ptr = 42; // Crucially, only a write is printed here, no read!
diff --git a/src/tools/miri/tests/pass/alloc-access-tracking.stderr b/src/tools/miri/tests/pass/alloc-access-tracking.stderr
index 451f5de25d3..0c85afd831b 100644
--- a/src/tools/miri/tests/pass/alloc-access-tracking.stderr
+++ b/src/tools/miri/tests/pass/alloc-access-tracking.stderr
@@ -5,7 +5,7 @@ LL |         let ptr = miri_alloc(123, 1);
    |                   ^^^^^^^^^^^^^^^^^^ created Miri bare-metal heap allocation of 123 bytes (alignment ALIGN bytes) with id $ALLOC
    |
    = note: BACKTRACE:
-   = note: inside `start` at tests/pass/alloc-access-tracking.rs:LL:CC
+   = note: inside `miri_start` at tests/pass/alloc-access-tracking.rs:LL:CC
 
 note: tracking was triggered
   --> tests/pass/alloc-access-tracking.rs:LL:CC
@@ -14,7 +14,7 @@ LL |         *ptr = 42; // Crucially, only a write is printed here, no read!
    |         ^^^^^^^^^ write access to allocation with id $ALLOC
    |
    = note: BACKTRACE:
-   = note: inside `start` at tests/pass/alloc-access-tracking.rs:LL:CC
+   = note: inside `miri_start` at tests/pass/alloc-access-tracking.rs:LL:CC
 
 note: tracking was triggered
   --> tests/pass/alloc-access-tracking.rs:LL:CC
@@ -23,7 +23,7 @@ LL |         assert_eq!(*ptr, 42);
    |         ^^^^^^^^^^^^^^^^^^^^ read access to allocation with id $ALLOC
    |
    = note: BACKTRACE:
-   = note: inside `start` at RUSTLIB/core/src/macros/mod.rs:LL:CC
+   = note: inside `miri_start` at RUSTLIB/core/src/macros/mod.rs:LL:CC
    = note: this note originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: tracking was triggered
@@ -33,5 +33,5 @@ LL |         miri_dealloc(ptr, 123, 1);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ freed allocation with id $ALLOC
    |
    = note: BACKTRACE:
-   = note: inside `start` at tests/pass/alloc-access-tracking.rs:LL:CC
+   = note: inside `miri_start` at tests/pass/alloc-access-tracking.rs:LL:CC
 
diff --git a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
index acd3502f528..0d0d79098d5 100644
--- a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
+++ b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
@@ -14,10 +14,9 @@ use std::ptr;
 use std::simd::StdFloat;
 use std::simd::prelude::*;
 
-extern "rust-intrinsic" {
-    #[rustc_nounwind]
-    pub fn simd_shuffle_generic<T, U, const IDX: &'static [u32]>(x: T, y: T) -> U;
-}
+#[rustc_intrinsic]
+#[rustc_nounwind]
+pub unsafe fn simd_shuffle_generic<T, U, const IDX: &'static [u32]>(_x: T, _y: T) -> U;
 
 fn simd_ops_f32() {
     let a = f32x4::splat(10.0);
diff --git a/src/tools/miri/tests/pass/miri-alloc.rs b/src/tools/miri/tests/pass/miri-alloc.rs
index 17f6d5d05a5..20269d8ced0 100644
--- a/src/tools/miri/tests/pass/miri-alloc.rs
+++ b/src/tools/miri/tests/pass/miri-alloc.rs
@@ -1,5 +1,5 @@
-#![feature(start)]
 #![no_std]
+#![no_main]
 //@compile-flags: -Cpanic=abort
 // windows tls dtors go through libstd right now, thus this test
 // cannot pass. When windows tls dtors go through the special magic
@@ -11,8 +11,8 @@ extern "Rust" {
     fn miri_dealloc(ptr: *mut u8, size: usize, align: usize);
 }
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
     unsafe {
         let ptr = miri_alloc(123, 1);
         core::ptr::write_bytes(ptr, 0u8, 123);
diff --git a/src/tools/miri/tests/pass/miri_start.stdout b/src/tools/miri/tests/pass/miri_start.stdout
deleted file mode 100644
index 1c9e8489b57..00000000000
--- a/src/tools/miri/tests/pass/miri_start.stdout
+++ /dev/null
@@ -1 +0,0 @@
-Hello from miri_start!
diff --git a/src/tools/miri/tests/pass/no_std.rs b/src/tools/miri/tests/pass/no_std.rs
deleted file mode 100644
index fc1c16f5fb9..00000000000
--- a/src/tools/miri/tests/pass/no_std.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-//@compile-flags: -Cpanic=abort
-#![feature(start)]
-#![no_std]
-
-use core::fmt::Write;
-
-#[path = "../utils/mod.no_std.rs"]
-mod utils;
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
-    writeln!(utils::MiriStdout, "hello, world!").unwrap();
-    0
-}
-
-#[panic_handler]
-fn panic_handler(_: &core::panic::PanicInfo) -> ! {
-    loop {}
-}
diff --git a/src/tools/miri/tests/pass/miri_start.rs b/src/tools/miri/tests/pass/no_std_miri_start.rs
index 756a1f60be1..cf9636b9d8c 100644
--- a/src/tools/miri/tests/pass/miri_start.rs
+++ b/src/tools/miri/tests/pass/no_std_miri_start.rs
@@ -1,6 +1,6 @@
 //@compile-flags: -Cpanic=abort
-#![no_main]
 #![no_std]
+#![no_main]
 
 use core::fmt::Write;
 
@@ -9,7 +9,7 @@ mod utils;
 
 #[no_mangle]
 fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
-    writeln!(utils::MiriStdout, "Hello from miri_start!").unwrap();
+    writeln!(utils::MiriStdout, "hello, world!").unwrap();
     0
 }
 
diff --git a/src/tools/miri/tests/pass/no_std.stdout b/src/tools/miri/tests/pass/no_std_miri_start.stdout
index 270c611ee72..270c611ee72 100644
--- a/src/tools/miri/tests/pass/no_std.stdout
+++ b/src/tools/miri/tests/pass/no_std_miri_start.stdout
diff --git a/src/tools/miri/tests/pass/shims/pipe.rs b/src/tools/miri/tests/pass/shims/pipe.rs
new file mode 100644
index 00000000000..1be29886d2d
--- /dev/null
+++ b/src/tools/miri/tests/pass/shims/pipe.rs
@@ -0,0 +1,13 @@
+//@ignore-target: windows
+
+#![feature(anonymous_pipe)]
+
+use std::io::{Read, Write, pipe};
+
+fn main() {
+    let (mut ping_rx, mut ping_tx) = pipe().unwrap();
+    ping_tx.write(b"hello").unwrap();
+    let mut buf: [u8; 5] = [0; 5];
+    ping_rx.read(&mut buf).unwrap();
+    assert_eq!(&buf, "hello".as_bytes());
+}
diff --git a/src/tools/miri/tests/pass/start.rs b/src/tools/miri/tests/pass/start.rs
deleted file mode 100644
index f25d62fa8c3..00000000000
--- a/src/tools/miri/tests/pass/start.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-#![feature(start)]
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
-    println!("Hello from start!");
-
-    0
-}
diff --git a/src/tools/miri/tests/pass/start.stdout b/src/tools/miri/tests/pass/start.stdout
deleted file mode 100644
index d7f627d237c..00000000000
--- a/src/tools/miri/tests/pass/start.stdout
+++ /dev/null
@@ -1 +0,0 @@
-Hello from start!
diff --git a/src/tools/miri/triagebot.toml b/src/tools/miri/triagebot.toml
index 3192882dff6..4e013764d87 100644
--- a/src/tools/miri/triagebot.toml
+++ b/src/tools/miri/triagebot.toml
@@ -1,3 +1,6 @@
+## See <https://forge.rust-lang.org/triagebot/index.html> for documentation
+## of these options.
+
 [relabel]
 allow-unauthenticated = [
     "A-*",
@@ -30,5 +33,10 @@ remove_labels = ["S-waiting-on-author"]
 # Those labels are added when PR author requests a review from an assignee
 add_labels = ["S-waiting-on-review"]
 
+[merge-conflicts]
+remove = []
+add = ["S-waiting-on-author"]
+unless = ["S-blocked", "S-waiting-on-team", "S-waiting-on-review"]
+
 # Automatically close and reopen PRs made by bots to run CI on them
 [bot-pull-requests]
diff --git a/src/tools/opt-dist/src/tests.rs b/src/tools/opt-dist/src/tests.rs
index 06ed076a864..8b3bd77141b 100644
--- a/src/tools/opt-dist/src/tests.rs
+++ b/src/tools/opt-dist/src/tests.rs
@@ -69,6 +69,7 @@ change-id = 115898
 
 [rust]
 channel = "{channel}"
+verbose-tests = true
 
 [build]
 rustc = "{rustc}"
@@ -102,13 +103,19 @@ llvm-config = "{llvm_config}"
         "tests/incremental",
         "tests/mir-opt",
         "tests/pretty",
+        "tests/run-make/glibc-symbols-x86_64-unknown-linux-gnu",
         "tests/ui",
         "tests/crashes",
     ];
     for test_path in env.skipped_tests() {
         args.extend(["--skip", test_path]);
     }
-    cmd(&args).env("COMPILETEST_FORCE_STAGE0", "1").run().context("Cannot execute tests")
+    cmd(&args)
+        .env("COMPILETEST_FORCE_STAGE0", "1")
+        // Also run dist-only tests
+        .env("COMPILETEST_ENABLE_DIST_TESTS", "1")
+        .run()
+        .context("Cannot execute tests")
 }
 
 /// Tries to find the version of the dist artifacts (either nightly, beta, or 1.XY.Z).
diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs
index e73413085fa..b4dc753ab53 100644
--- a/src/tools/run-make-support/src/command.rs
+++ b/src/tools/run-make-support/src/command.rs
@@ -151,6 +151,61 @@ impl Command {
         self
     }
 
+    /// Set an auxiliary stream passed to the process, besides the stdio streams.
+    ///
+    /// # Notes
+    ///
+    /// Use with caution! Ideally, only set one aux fd; if there are multiple, their old `fd` may
+    /// overlap with another's `new_fd`, and may break. The caller must make sure this is not the
+    /// case. This function is only "safe" because the safety requirements are practically not
+    /// possible to uphold.
+    #[cfg(unix)]
+    pub fn set_aux_fd<F: Into<std::os::fd::OwnedFd>>(
+        &mut self,
+        new_fd: std::os::fd::RawFd,
+        fd: F,
+    ) -> &mut Self {
+        use std::mem;
+        // NOTE: If more than 1 auxiliary file descriptor is needed, this function should be
+        // rewritten.
+        use std::os::fd::AsRawFd;
+        use std::os::unix::process::CommandExt;
+
+        let cvt = |x| if x == -1 { Err(std::io::Error::last_os_error()) } else { Ok(()) };
+
+        // Ensure fd stays open until the fork.
+        let fd = mem::ManuallyDrop::new(fd.into());
+        let fd = fd.as_raw_fd();
+
+        if fd == new_fd {
+            // If the new file descriptor is already the same as fd, just turn off `FD_CLOEXEC`.
+            let fd_flags = {
+                let ret = unsafe { libc::fcntl(fd, libc::F_GETFD, 0) };
+                if ret < 0 {
+                    panic!("failed to read fd flags: {}", std::io::Error::last_os_error());
+                }
+                ret
+            };
+            // Clear `FD_CLOEXEC`.
+            let fd_flags = fd_flags & !libc::FD_CLOEXEC;
+
+            // SAFETY(io-safety): `fd` is already owned.
+            cvt(unsafe { libc::fcntl(fd, libc::F_SETFD, fd_flags as libc::c_int) })
+                .expect("disabling CLOEXEC failed");
+        }
+        let pre_exec = move || {
+            if fd.as_raw_fd() != new_fd {
+                // SAFETY(io-safety): it's the caller's responsibility that we won't override the
+                // target fd.
+                cvt(unsafe { libc::dup2(fd, new_fd) })?;
+            }
+            Ok(())
+        };
+        // SAFETY(pre-exec-safe): `dup2` is pre-exec-safe.
+        unsafe { self.cmd.pre_exec(pre_exec) };
+        self
+    }
+
     /// Run the constructed command and assert that it is successfully run.
     ///
     /// By default, std{in,out,err} are [`Stdio::piped()`].
diff --git a/src/tools/run-make-support/src/macros.rs b/src/tools/run-make-support/src/macros.rs
index cc3d1281d0a..94955aefe57 100644
--- a/src/tools/run-make-support/src/macros.rs
+++ b/src/tools/run-make-support/src/macros.rs
@@ -104,6 +104,17 @@ macro_rules! impl_common_helpers {
                 self
             }
 
+            /// Set an auxiliary stream passed to the process, besides the stdio streams.
+            #[cfg(unix)]
+            pub fn set_aux_fd<F: Into<std::os::fd::OwnedFd>>(
+                &mut self,
+                new_fd: std::os::fd::RawFd,
+                fd: F,
+            ) -> &mut Self {
+                self.cmd.set_aux_fd(new_fd, fd);
+                self
+            }
+
             /// Run the constructed command and assert that it is successfully run.
             #[track_caller]
             pub fn run(&mut self) -> crate::command::CompletedProcess {
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 48b5f3aabfc..f92668a6a97 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -98,9 +98,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bitflags"
-version = "2.6.0"
+version = "2.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be"
 
 [[package]]
 name = "borsh"
@@ -194,9 +194,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
 
 [[package]]
 name = "chalk-derive"
-version = "0.98.0"
+version = "0.99.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9426c8fd0fe61c3da880b801d3b510524df17843a8f9ec1f5b9cec24fb7412df"
+checksum = "572583d9b97f9d277e5c7607f8239a30e2e04d3ed3b47c87d1cb2152ae724073"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -206,19 +206,19 @@ dependencies = [
 
 [[package]]
 name = "chalk-ir"
-version = "0.98.0"
+version = "0.99.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5f2eb1cd6054da221bd1ac0197fb2fe5e2caf3dcb93619398fc1433f8f09093"
+checksum = "e60e0ef9c81dce1336a9ed3c76f08775f5b623151d96d85ba45f7b10de76d1c7"
 dependencies = [
- "bitflags 2.6.0",
+ "bitflags 2.7.0",
  "chalk-derive",
 ]
 
 [[package]]
 name = "chalk-recursive"
-version = "0.98.0"
+version = "0.99.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "129dc03458f71cfb9c3cd621c9c68166a94e87b85b16ccd29af015d7ff9a1c61"
+checksum = "5a06350d614e22b03a69b8105e3541614450a7ea48bc58ecc6c6bd92731a3995"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -229,9 +229,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-solve"
-version = "0.98.0"
+version = "0.99.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7e8a8c1e928f98cdf227b868416ef21dcd8cc3c61b347576d783713444d41c8"
+checksum = "0e428761e9b55bee516bfe2457caed8b6d1b86353f92ae825bbe438a36ce91e8"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -523,6 +523,7 @@ dependencies = [
  "hir-def",
  "hir-expand",
  "hir-ty",
+ "indexmap",
  "intern",
  "itertools",
  "rustc-hash 2.0.0",
@@ -544,7 +545,7 @@ version = "0.0.0"
 dependencies = [
  "arrayvec",
  "base-db",
- "bitflags 2.6.0",
+ "bitflags 2.7.0",
  "cfg",
  "cov-mark",
  "dashmap",
@@ -610,7 +611,7 @@ version = "0.0.0"
 dependencies = [
  "arrayvec",
  "base-db",
- "bitflags 2.6.0",
+ "bitflags 2.7.0",
  "chalk-derive",
  "chalk-ir",
  "chalk-recursive",
@@ -734,7 +735,7 @@ version = "0.0.0"
 dependencies = [
  "arrayvec",
  "base-db",
- "bitflags 2.6.0",
+ "bitflags 2.7.0",
  "cov-mark",
  "crossbeam-channel",
  "either",
@@ -820,11 +821,11 @@ dependencies = [
 
 [[package]]
 name = "inotify"
-version = "0.9.6"
+version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff"
+checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3"
 dependencies = [
- "bitflags 1.3.2",
+ "bitflags 2.7.0",
  "inotify-sys",
  "libc",
 ]
@@ -908,9 +909,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
 
 [[package]]
 name = "libc"
-version = "0.2.155"
+version = "0.2.169"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
+checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
 
 [[package]]
 name = "libloading"
@@ -938,7 +939,7 @@ version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
 dependencies = [
- "bitflags 2.6.0",
+ "bitflags 2.7.0",
  "libc",
  "redox_syscall",
 ]
@@ -1117,14 +1118,14 @@ dependencies = [
 
 [[package]]
 name = "mio"
-version = "0.8.11"
+version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
+checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
 dependencies = [
  "libc",
  "log",
  "wasi",
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -1142,7 +1143,7 @@ version = "0.28.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
 dependencies = [
- "bitflags 2.6.0",
+ "bitflags 2.7.0",
  "cfg-if",
  "cfg_aliases 0.1.1",
  "libc",
@@ -1156,12 +1157,11 @@ checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
 
 [[package]]
 name = "notify"
-version = "6.1.1"
+version = "8.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d"
+checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943"
 dependencies = [
- "bitflags 2.6.0",
- "crossbeam-channel",
+ "bitflags 2.7.0",
  "filetime",
  "fsevent-sys",
  "inotify",
@@ -1169,11 +1169,18 @@ dependencies = [
  "libc",
  "log",
  "mio",
+ "notify-types",
  "walkdir",
- "windows-sys 0.48.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
+name = "notify-types"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d"
+
+[[package]]
 name = "nu-ansi-term"
 version = "0.50.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1371,6 +1378,7 @@ version = "0.0.0"
 dependencies = [
  "expect-test",
  "intern",
+ "libc",
  "libloading",
  "memmap2",
  "object 0.33.0",
@@ -1428,7 +1436,7 @@ dependencies = [
  "libc",
  "perf-event",
  "tikv-jemalloc-ctl",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -1482,7 +1490,7 @@ version = "0.9.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b"
 dependencies = [
- "bitflags 2.6.0",
+ "bitflags 2.7.0",
  "memchr",
  "unicase",
 ]
@@ -1507,20 +1515,20 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_abi"
-version = "0.87.0"
+version = "0.91.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28b782af0a7a8df16ddf43cd70da9f17bc3b1ce712c9e4992b6edb16f5f53632"
+checksum = "d5246e9e1f450333a990877eabbc36fe0567e7cedd56d5365db319e14079cf2a"
 dependencies = [
- "bitflags 2.6.0",
+ "bitflags 2.7.0",
  "ra-ap-rustc_index",
  "tracing",
 ]
 
 [[package]]
 name = "ra-ap-rustc_index"
-version = "0.87.0"
+version = "0.91.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce5742f134960482f543b35ecebec3cacc6d79a9a685713518b4d8d70c5f9aa8"
+checksum = "59fd8e4f5b34c434ec111efb0e0614954db048b9307d3b2e4cc3c915da9d2160"
 dependencies = [
  "ra-ap-rustc_index_macros",
  "smallvec",
@@ -1528,9 +1536,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_index_macros"
-version = "0.87.0"
+version = "0.91.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7ea011fcf68309a8835ad01d91c032cb18444617b00e2cab21d45b208164441"
+checksum = "2d34973fe081392bd1edb022e865e9952fcaa093f9cdae183edce64472e5e889"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1539,9 +1547,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_lexer"
-version = "0.87.0"
+version = "0.91.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb76f0a4d4c20859e41f0a23bff0f37ab9ca9171c214a6c7dd72ea69434865dc"
+checksum = "52fa42c582e21b35e8f61a5afe3c63a9c722d995826762eb19b18beeccf5157f"
 dependencies = [
  "unicode-properties",
  "unicode-xid",
@@ -1549,9 +1557,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_parse_format"
-version = "0.87.0"
+version = "0.91.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06080bd35078305421a62da77f3c128482d8d44441b6da8ce9d146d1cd9cdb5b"
+checksum = "740383328d7033393e5385f4a6073b880d5811b0fc0fd2559e481f905940f2f8"
 dependencies = [
  "ra-ap-rustc_index",
  "ra-ap-rustc_lexer",
@@ -1559,9 +1567,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_pattern_analysis"
-version = "0.87.0"
+version = "0.91.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68a3154fe4c20c177d7b3c678a2d3a97aba0cca156ddef88959915041889daf0"
+checksum = "c39f544728f32cebffb1a8b92ba3c1f3dcb4144081438d192137ed197d479a9d"
 dependencies = [
  "ra-ap-rustc_index",
  "rustc-hash 2.0.0",
@@ -1626,7 +1634,7 @@ version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
 dependencies = [
- "bitflags 2.6.0",
+ "bitflags 2.7.0",
 ]
 
 [[package]]
@@ -1713,7 +1721,7 @@ dependencies = [
  "vfs",
  "vfs-notify",
  "walkdir",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
  "xflags",
  "xshell",
 ]
@@ -1936,7 +1944,7 @@ dependencies = [
  "jod-thread",
  "libc",
  "miow",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 9440123de70..1029844cd3a 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -4,7 +4,7 @@ exclude = ["crates/proc-macro-srv/proc-macro-test/imp"]
 resolver = "2"
 
 [workspace.package]
-rust-version = "1.82"
+rust-version = "1.83"
 edition = "2021"
 license = "MIT OR Apache-2.0"
 authors = ["rust-analyzer team"]
@@ -79,6 +79,7 @@ span = { path = "./crates/span", version = "0.0.0" }
 stdx = { path = "./crates/stdx", version = "0.0.0" }
 syntax = { path = "./crates/syntax", version = "0.0.0" }
 syntax-bridge = { path = "./crates/syntax-bridge", version = "0.0.0" }
+test-fixture = { path = "./crates/test-fixture", version = "0.0.0" }
 test-utils = { path = "./crates/test-utils", version = "0.0.0" }
 toolchain = { path = "./crates/toolchain", version = "0.0.0" }
 tt = { path = "./crates/tt", version = "0.0.0" }
@@ -86,16 +87,15 @@ 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_lexer = { version = "0.87", default-features = false }
-ra-ap-rustc_parse_format = { version = "0.87", default-features = false }
-ra-ap-rustc_index = { version = "0.87", default-features = false }
-ra-ap-rustc_abi = { version = "0.87", default-features = false }
-ra-ap-rustc_pattern_analysis = { version = "0.87", default-features = false }
+ra-ap-rustc_lexer = { version = "0.91", default-features = false }
+ra-ap-rustc_parse_format = { version = "0.91", default-features = false }
+ra-ap-rustc_index = { version = "0.91", default-features = false }
+ra-ap-rustc_abi = { version = "0.91", default-features = false }
+ra-ap-rustc_pattern_analysis = { version = "0.91", default-features = false }
 
 # local crates that aren't published to crates.io. These should not have versions.
-test-fixture = { path = "./crates/test-fixture" }
 
-# In-tree crates that are published separately and follow semver. See lib/README.md
+# in-tree crates that are published separately and follow semver. See lib/README.md
 line-index = { version = "0.1.2" }
 la-arena = { version = "0.3.1" }
 lsp-server = { version = "0.7.6" }
@@ -106,10 +106,10 @@ arrayvec = "0.7.4"
 bitflags = "2.4.1"
 cargo_metadata = "0.18.1"
 camino = "1.1.6"
-chalk-solve = { version = "0.98.0", default-features = false }
-chalk-ir = "0.98.0"
-chalk-recursive = { version = "0.98.0", default-features = false }
-chalk-derive = "0.98.0"
+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"
 crossbeam-channel = "0.5.8"
 dissimilar = "1.0.7"
 dot = "0.1.4"
diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
index 0a9e83bc3ba..c7e4168f6bc 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
@@ -136,7 +136,7 @@ pub trait SourceRootDatabase: SourceDatabase {
     #[ra_salsa::input]
     fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>;
 
-    /// Crates whose root fool is in `id`.
+    /// Crates whose root file is in `id`.
     fn source_root_crates(&self, id: SourceRootId) -> Arc<[CrateId]>;
 }
 
diff --git a/src/tools/rust-analyzer/crates/edition/src/lib.rs b/src/tools/rust-analyzer/crates/edition/src/lib.rs
index c25d5b9557b..7e9c94af408 100644
--- a/src/tools/rust-analyzer/crates/edition/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/edition/src/lib.rs
@@ -5,7 +5,8 @@ use std::fmt;
 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[repr(u8)]
 pub enum Edition {
-    Edition2015,
+    // The syntax context stuff needs the discriminants to start from 0 and be consecutive.
+    Edition2015 = 0,
     Edition2018,
     Edition2021,
     Edition2024,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
index 37e2a99e60f..710bffcefe9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
@@ -122,6 +122,11 @@ impl Attrs {
         AttrQuery { attrs: self, key }
     }
 
+    pub fn rust_analyzer_tool(&self) -> impl Iterator<Item = &Attr> {
+        self.iter()
+            .filter(|&attr| attr.path.segments().first().is_some_and(|s| *s == sym::rust_analyzer))
+    }
+
     pub fn cfg(&self) -> Option<CfgExpr> {
         let mut cfgs = self.by_key(&sym::cfg).tt_values().map(CfgExpr::parse);
         let first = cfgs.next()?;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
index 433a956ff9a..de439249306 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
@@ -15,7 +15,7 @@ use hir_expand::{name::Name, ExpandError, InFile};
 use la_arena::{Arena, ArenaMap, Idx, RawIdx};
 use rustc_hash::FxHashMap;
 use smallvec::SmallVec;
-use span::{Edition, MacroFileId};
+use span::{Edition, MacroFileId, SyntaxContextData};
 use syntax::{ast, AstPtr, SyntaxNodePtr};
 use triomphe::Arc;
 use tt::TextRange;
@@ -37,15 +37,22 @@ use crate::{
 
 /// A wrapper around [`span::SyntaxContextId`] that is intended only for comparisons.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct HygieneId(pub(crate) span::SyntaxContextId);
+pub struct HygieneId(span::SyntaxContextId);
 
 impl HygieneId {
-    pub const ROOT: Self = Self(span::SyntaxContextId::ROOT);
+    // The edition doesn't matter here, we only use this for comparisons and to lookup the macro.
+    pub const ROOT: Self = Self(span::SyntaxContextId::root(Edition::Edition2015));
 
-    pub fn new(ctx: span::SyntaxContextId) -> Self {
+    pub fn new(mut ctx: span::SyntaxContextId) -> Self {
+        // See `Name` for why we're doing that.
+        ctx.remove_root_edition();
         Self(ctx)
     }
 
+    pub(crate) fn lookup(self, db: &dyn DefDatabase) -> SyntaxContextData {
+        db.lookup_intern_syntax_context(self.0)
+    }
+
     pub(crate) fn is_root(self) -> bool {
         self.0.is_root()
     }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
index 10b84d041bd..1327bb3ab59 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
@@ -8,6 +8,7 @@ use std::mem;
 use base_db::CrateId;
 use either::Either;
 use hir_expand::{
+    mod_path::tool_path,
     name::{AsName, Name},
     span_map::{ExpansionSpanMap, SpanMap},
     InFile, MacroDefId,
@@ -27,6 +28,7 @@ use text_size::TextSize;
 use triomphe::Arc;
 
 use crate::{
+    attr::Attrs,
     body::{Body, BodyDiagnostic, BodySourceMap, ExprPtr, HygieneId, LabelPtr, PatPtr},
     builtin_type::BuiltinUint,
     data::adt::StructKind,
@@ -212,6 +214,43 @@ impl ExprCollector<'_> {
         body: Option<ast::Expr>,
         is_async_fn: bool,
     ) -> (Body, BodySourceMap) {
+        let skip_body = match self.owner {
+            DefWithBodyId::FunctionId(it) => self.db.attrs(it.into()),
+            DefWithBodyId::StaticId(it) => self.db.attrs(it.into()),
+            DefWithBodyId::ConstId(it) => self.db.attrs(it.into()),
+            DefWithBodyId::InTypeConstId(_) => Attrs::EMPTY,
+            DefWithBodyId::VariantId(it) => self.db.attrs(it.into()),
+        }
+        .rust_analyzer_tool()
+        .any(|attr| *attr.path() == tool_path![skip]);
+        // If #[rust_analyzer::skip] annotated, only construct enough information for the signature
+        // and skip the body.
+        if skip_body {
+            self.body.body_expr = self.missing_expr();
+            if let Some((param_list, mut attr_enabled)) = param_list {
+                if let Some(self_param) =
+                    param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false))
+                {
+                    let is_mutable =
+                        self_param.mut_token().is_some() && self_param.amp_token().is_none();
+                    let binding_id: la_arena::Idx<Binding> = self.alloc_binding(
+                        Name::new_symbol_root(sym::self_.clone()),
+                        BindingAnnotation::new(is_mutable, false),
+                    );
+                    self.body.self_param = Some(binding_id);
+                    self.source_map.self_param =
+                        Some(self.expander.in_file(AstPtr::new(&self_param)));
+                }
+                self.body.params = param_list
+                    .params()
+                    .zip(attr_enabled)
+                    .filter(|(_, enabled)| *enabled)
+                    .map(|_| self.missing_pat())
+                    .collect();
+            };
+            return (self.body, self.source_map);
+        }
+
         self.awaitable_context.replace(if is_async_fn {
             Awaitable::Yes
         } else {
@@ -542,10 +581,7 @@ impl ExprCollector<'_> {
                 let mutability = if raw_tok {
                     if e.mut_token().is_some() {
                         Mutability::Mut
-                    } else if e.const_token().is_some() {
-                        Mutability::Shared
                     } else {
-                        never!("parser only remaps to raw_token() if matching mutability token follows");
                         Mutability::Shared
                     }
                 } else {
@@ -2460,7 +2496,7 @@ impl ExprCollector<'_> {
             None => HygieneId::ROOT,
             Some(span_map) => {
                 let ctx = span_map.span_at(span_start).ctx;
-                HygieneId(self.db.lookup_intern_syntax_context(ctx).opaque_and_semitransparent)
+                HygieneId::new(self.db.lookup_intern_syntax_context(ctx).opaque_and_semitransparent)
             }
         }
     }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
index 63a7a9af201..08af470b965 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
@@ -345,7 +345,7 @@ mod tests {
         }
     }
 
-    fn do_check(ra_fixture: &str, expected: &[&str]) {
+    fn do_check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected: &[&str]) {
         let (offset, code) = extract_offset(ra_fixture);
         let code = {
             let mut buf = String::new();
@@ -509,7 +509,7 @@ fn foo() {
         );
     }
 
-    fn do_check_local_name(ra_fixture: &str, expected_offset: u32) {
+    fn do_check_local_name(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected_offset: u32) {
         let (db, position) = TestDB::with_position(ra_fixture);
         let file_id = position.file_id;
         let offset = position.offset;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
index 7e15a9f2d61..edc7c4c1f21 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
@@ -7,7 +7,7 @@ use crate::{test_db::TestDB, ModuleDefId};
 
 use super::*;
 
-fn lower(ra_fixture: &str) -> (TestDB, Arc<Body>, DefWithBodyId) {
+fn lower(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (TestDB, Arc<Body>, DefWithBodyId) {
     let db = TestDB::with_files(ra_fixture);
 
     let krate = db.fetch_test_crate();
@@ -27,14 +27,14 @@ fn lower(ra_fixture: &str) -> (TestDB, Arc<Body>, DefWithBodyId) {
     (db, body, fn_def)
 }
 
-fn def_map_at(ra_fixture: &str) -> String {
+fn def_map_at(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String {
     let (db, position) = TestDB::with_position(ra_fixture);
 
     let module = db.module_at_position(position);
     module.def_map(&db).dump(&db)
 }
 
-fn check_block_scopes_at(ra_fixture: &str, expect: Expect) {
+fn check_block_scopes_at(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let (db, position) = TestDB::with_position(ra_fixture);
 
     let module = db.module_at_position(position);
@@ -42,7 +42,7 @@ fn check_block_scopes_at(ra_fixture: &str, expect: Expect) {
     expect.assert_eq(&actual);
 }
 
-fn check_at(ra_fixture: &str, expect: Expect) {
+fn check_at(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let actual = def_map_at(ra_fixture);
     expect.assert_eq(&actual);
 }
@@ -444,3 +444,18 @@ fn foo() {
 }"#
     );
 }
+
+#[test]
+fn skip_skips_body() {
+    let (db, body, owner) = lower(
+        r#"
+#[rust_analyzer::skip]
+async fn foo(a: (), b: i32) -> u32 {
+    0 + 1 + b()
+}
+"#,
+    );
+    let printed = body.pretty_print(&db, owner, Edition::CURRENT);
+    expect!["fn foo(�: (), �: i32) -> impl ::core::future::Future::<Output = u32> �"]
+        .assert_eq(&printed);
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
index d85bc9a4320..12f5f6ad79a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -244,7 +244,7 @@ bitflags::bitflags! {
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct TraitData {
     pub name: Name,
-    pub items: Vec<(Name, AssocItemId)>,
+    pub items: Box<[(Name, AssocItemId)]>,
     pub flags: TraitFlags,
     pub visibility: RawVisibility,
     // box it as the vec is usually empty anyways
@@ -360,7 +360,7 @@ impl TraitAliasData {
 pub struct ImplData {
     pub target_trait: Option<TraitRef>,
     pub self_ty: TypeRefId,
-    pub items: Box<[AssocItemId]>,
+    pub items: Box<[(Name, AssocItemId)]>,
     pub is_negative: bool,
     pub is_unsafe: bool,
     // box it as the vec is usually empty anyways
@@ -393,7 +393,6 @@ impl ImplData {
         collector.collect(&item_tree, tree_id.tree_id(), &impl_def.items);
 
         let (items, macro_calls, diagnostics) = collector.finish();
-        let items = items.into_iter().map(|(_, item)| item).collect();
 
         (
             Arc::new(ImplData {
@@ -648,12 +647,12 @@ impl<'a> AssocItemCollector<'a> {
     fn finish(
         self,
     ) -> (
-        Vec<(Name, AssocItemId)>,
+        Box<[(Name, AssocItemId)]>,
         Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
         Vec<DefDiagnostic>,
     ) {
         (
-            self.items,
+            self.items.into_boxed_slice(),
             if self.macro_calls.is_empty() { None } else { Some(Box::new(self.macro_calls)) },
             self.diagnostics,
         )
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
index 5315c1c6fbd..108258d5a11 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
@@ -10,7 +10,7 @@ use hir_expand::{
     ExpandResult, HirFileId, InFile, Lookup, MacroCallId,
 };
 use limit::Limit;
-use span::SyntaxContextId;
+use span::{Edition, SyntaxContextId};
 use syntax::{ast, Parse};
 use triomphe::Arc;
 
@@ -60,7 +60,7 @@ impl Expander {
 
     pub fn syntax_context(&self) -> SyntaxContextId {
         // FIXME:
-        SyntaxContextId::ROOT
+        SyntaxContextId::root(Edition::CURRENT)
     }
 
     pub fn enter_expand<T: ast::AstNode>(
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
index a615abd1bbe..5d67902c8ac 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
@@ -665,7 +665,7 @@ mod tests {
     /// module the cursor is in.
     #[track_caller]
     fn check_found_path_(
-        ra_fixture: &str,
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
         path: &str,
         prefer_prelude: bool,
         prefer_absolute: bool,
@@ -727,19 +727,35 @@ mod tests {
         expect.assert_eq(&res);
     }
 
-    fn check_found_path(ra_fixture: &str, path: &str, expect: Expect) {
+    fn check_found_path(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        path: &str,
+        expect: Expect,
+    ) {
         check_found_path_(ra_fixture, path, false, false, false, expect);
     }
 
-    fn check_found_path_prelude(ra_fixture: &str, path: &str, expect: Expect) {
+    fn check_found_path_prelude(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        path: &str,
+        expect: Expect,
+    ) {
         check_found_path_(ra_fixture, path, true, false, false, expect);
     }
 
-    fn check_found_path_absolute(ra_fixture: &str, path: &str, expect: Expect) {
+    fn check_found_path_absolute(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        path: &str,
+        expect: Expect,
+    ) {
         check_found_path_(ra_fixture, path, false, true, false, expect);
     }
 
-    fn check_found_path_prefer_no_std(ra_fixture: &str, path: &str, expect: Expect) {
+    fn check_found_path_prefer_no_std(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        path: &str,
+        expect: Expect,
+    ) {
         check_found_path_(ra_fixture, path, false, false, true, expect);
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
index 9574e5d9cd3..ac262950f13 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
@@ -509,7 +509,12 @@ mod tests {
         }
     }
 
-    fn check_search(ra_fixture: &str, crate_name: &str, query: Query, expect: Expect) {
+    fn check_search(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        crate_name: &str,
+        query: Query,
+        expect: Expect,
+    ) {
         let db = TestDB::with_files(ra_fixture);
         let crate_graph = db.crate_graph();
         let krate = crate_graph
@@ -587,7 +592,7 @@ mod tests {
         ))
     }
 
-    fn check(ra_fixture: &str, expect: Expect) {
+    fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
         let db = TestDB::with_files(ra_fixture);
         let crate_graph = db.crate_graph();
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
index 2c3eb5c8e5e..0fec7674109 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
@@ -162,6 +162,20 @@ impl ItemScope {
             .map(move |name| (name, self.get(name)))
     }
 
+    pub fn values(&self) -> impl Iterator<Item = (&Name, Item<ModuleDefId, ImportId>)> + '_ {
+        self.values.iter().map(|(n, &i)| (n, i))
+    }
+
+    pub fn types(
+        &self,
+    ) -> impl Iterator<Item = (&Name, Item<ModuleDefId, ImportOrExternCrate>)> + '_ {
+        self.types.iter().map(|(n, &i)| (n, i))
+    }
+
+    pub fn macros(&self) -> impl Iterator<Item = (&Name, Item<MacroId, ImportId>)> + '_ {
+        self.macros.iter().map(|(n, &i)| (n, i))
+    }
+
     pub fn imports(&self) -> impl Iterator<Item = ImportId> + '_ {
         self.use_imports_types
             .keys()
@@ -263,11 +277,6 @@ impl ItemScope {
         self.unnamed_consts.iter().copied()
     }
 
-    /// Iterate over all module scoped macros
-    pub(crate) fn macros(&self) -> impl Iterator<Item = (&Name, MacroId)> + '_ {
-        self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_)))
-    }
-
     /// Iterate over all legacy textual scoped macros visible at the end of the module
     pub fn legacy_macros(&self) -> impl Iterator<Item = (&Name, &[MacroId])> + '_ {
         self.legacy_macros.iter().map(|(name, def)| (name, &**def))
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
index 0f53969d6c7..80b699649fb 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
@@ -4,7 +4,7 @@ use test_fixture::WithFixture;
 
 use crate::{db::DefDatabase, test_db::TestDB};
 
-fn check(ra_fixture: &str, expect: Expect) {
+fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let (db, file_id) = TestDB::with_single_file(ra_fixture);
     let item_tree = db.file_item_tree(file_id.into());
     let pretty = item_tree.pretty_print(&db, Edition::CURRENT);
@@ -270,7 +270,7 @@ m!();
             // AstId: 2
             pub macro m2 { ... }
 
-            // AstId: 3, SyntaxContext: 0, ExpandTo: Items
+            // AstId: 3, SyntaxContext: 2, ExpandTo: Items
             m!(...);
         "#]],
     );
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
index 0629d87e544..afdc49a2dc5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
@@ -107,7 +107,7 @@ impl LangItems {
         for (_, module_data) in crate_def_map.modules() {
             for impl_def in module_data.scope.impls() {
                 lang_items.collect_lang_item(db, impl_def, LangItemTarget::ImplDef);
-                for assoc in db.impl_data(impl_def).items.iter().copied() {
+                for &(_, assoc) in db.impl_data(impl_def).items.iter() {
                     match assoc {
                         AssocItemId::FunctionId(f) => {
                             lang_items.collect_lang_item(db, f, LangItemTarget::Function)
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
index 8af27513ebc..84c105a0a34 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -502,7 +502,7 @@ impl ModuleId {
     }
 
     /// Whether this module represents the crate root module
-    fn is_crate_root(&self) -> bool {
+    pub fn is_crate_root(&self) -> bool {
         self.local_id == DefMap::ROOT && self.block.is_none()
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
index 511626b5ed9..8c5bd3b6d36 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
@@ -35,9 +35,9 @@ macro_rules! f {
     };
 }
 
-struct#0:1@58..64#1# MyTraitMap2#0:2@31..42#0# {#0:1@72..73#1#
-    map#0:1@86..89#1#:#0:1@89..90#1# #0:1@89..90#1#::#0:1@91..93#1#std#0:1@93..96#1#::#0:1@96..98#1#collections#0:1@98..109#1#::#0:1@109..111#1#HashSet#0:1@111..118#1#<#0:1@118..119#1#(#0:1@119..120#1#)#0:1@120..121#1#>#0:1@121..122#1#,#0:1@122..123#1#
-}#0:1@132..133#1#
+struct#0:1@58..64#4# MyTraitMap2#0:2@31..42#2# {#0:1@72..73#4#
+    map#0:1@86..89#4#:#0:1@89..90#4# #0:1@89..90#4#::#0:1@91..93#4#std#0:1@93..96#4#::#0:1@96..98#4#collections#0:1@98..109#4#::#0:1@109..111#4#HashSet#0:1@111..118#4#<#0:1@118..119#4#(#0:1@119..120#4#)#0:1@120..121#4#>#0:1@121..122#4#,#0:1@122..123#4#
+}#0:1@132..133#4#
 "#]],
     );
 }
@@ -75,12 +75,12 @@ macro_rules! f {
     };
 }
 
-fn#0:2@30..32#0# main#0:2@33..37#0#(#0:2@37..38#0#)#0:2@38..39#0# {#0:2@40..41#0#
-    1#0:2@50..51#0#;#0:2@51..52#0#
-    1.0#0:2@61..64#0#;#0:2@64..65#0#
-    (#0:2@74..75#0#(#0:2@75..76#0#1#0:2@76..77#0#,#0:2@77..78#0# )#0:2@78..79#0#,#0:2@79..80#0# )#0:2@80..81#0#.#0:2@81..82#0#0#0:2@82..85#0#.#0:2@82..85#0#0#0:2@82..85#0#;#0:2@85..86#0#
-    let#0:2@95..98#0# x#0:2@99..100#0# =#0:2@101..102#0# 1#0:2@103..104#0#;#0:2@104..105#0#
-}#0:2@110..111#0#
+fn#0:2@30..32#2# main#0:2@33..37#2#(#0:2@37..38#2#)#0:2@38..39#2# {#0:2@40..41#2#
+    1#0:2@50..51#2#;#0:2@51..52#2#
+    1.0#0:2@61..64#2#;#0:2@64..65#2#
+    (#0:2@74..75#2#(#0:2@75..76#2#1#0:2@76..77#2#,#0:2@77..78#2# )#0:2@78..79#2#,#0:2@79..80#2# )#0:2@80..81#2#.#0:2@81..82#2#0#0:2@82..85#2#.#0:2@82..85#2#0#0:2@82..85#2#;#0:2@85..86#2#
+    let#0:2@95..98#2# x#0:2@99..100#2# =#0:2@101..102#2# 1#0:2@103..104#2#;#0:2@104..105#2#
+}#0:2@110..111#2#
 
 
 "#]],
@@ -171,7 +171,7 @@ fn main(foo: ()) {
     }
 
     fn main(foo: ()) {
-        /* error: unresolved macro unresolved */"helloworld!"#0:3@236..321#0#;
+        /* error: unresolved macro unresolved */"helloworld!"#0:3@236..321#2#;
     }
 }
 
@@ -197,7 +197,7 @@ macro_rules! mk_struct {
 #[macro_use]
 mod foo;
 
-struct#1:1@59..65#1# Foo#0:2@32..35#0#(#1:1@70..71#1#u32#0:2@41..44#0#)#1:1@74..75#1#;#1:1@75..76#1#
+struct#1:1@59..65#4# Foo#0:2@32..35#2#(#1:1@70..71#4#u32#0:2@41..44#2#)#1:1@74..75#4#;#1:1@75..76#4#
 "#]],
     );
 }
@@ -423,10 +423,10 @@ m! { foo, bar }
 macro_rules! m {
     ($($i:ident),*) => ( impl Bar { $(fn $i() {})* } );
 }
-impl#\1# Bar#\1# {#\1#
-    fn#\1# foo#\0#(#\1#)#\1# {#\1#}#\1#
-    fn#\1# bar#\0#(#\1#)#\1# {#\1#}#\1#
-}#\1#
+impl#\4# Bar#\4# {#\4#
+    fn#\4# foo#\2#(#\4#)#\4# {#\4#}#\4#
+    fn#\4# bar#\2#(#\4#)#\4# {#\4#}#\4#
+}#\4#
 "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
index 5b9ffdf37be..408d03ff718 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -47,7 +47,7 @@ use crate::{
 };
 
 #[track_caller]
-fn check_errors(ra_fixture: &str, expect: Expect) {
+fn check_errors(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let db = TestDB::with_files(ra_fixture);
     let krate = db.fetch_test_crate();
     let def_map = db.crate_def_map(krate);
@@ -77,7 +77,7 @@ fn check_errors(ra_fixture: &str, expect: Expect) {
 }
 
 #[track_caller]
-fn check(ra_fixture: &str, mut expect: Expect) {
+fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, mut expect: Expect) {
     let extra_proc_macros = vec![(
         r#"
 #[proc_macro_attribute]
@@ -358,6 +358,7 @@ impl ProcMacroExpander for IdentityWhenValidProcMacroExpander {
         let (parse, _) = syntax_bridge::token_tree_to_syntax_node(
             subtree,
             syntax_bridge::TopEntryPoint::MacroItems,
+            &mut |_| span::Edition::CURRENT,
             span::Edition::CURRENT,
         );
         if parse.errors().is_empty() {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
index c0178adc9a6..70e3e1ed4e9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
@@ -181,9 +181,9 @@ fn foo(&self) {
     self.0. 1;
 }
 
-fn#0:1@45..47#0# foo#0:1@48..51#0#(#0:1@51..52#0#&#0:1@52..53#0#self#0:1@53..57#0# )#0:1@57..58#0# {#0:1@59..60#0#
-    self#0:1@65..69#0# .#0:1@69..70#0#0#0:1@70..71#0#.#0:1@71..72#0#1#0:1@73..74#0#;#0:1@74..75#0#
-}#0:1@76..77#0#"#]],
+fn#0:1@45..47#2# foo#0:1@48..51#2#(#0:1@51..52#2#&#0:1@52..53#2#self#0:1@53..57#2# )#0:1@57..58#2# {#0:1@59..60#2#
+    self#0:1@65..69#2# .#0:1@69..70#2#0#0:1@70..71#2#.#0:1@71..72#2#1#0:1@73..74#2#;#0:1@74..75#2#
+}#0:1@76..77#2#"#]],
     );
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index 8beeda82bca..1e4b42dff5f 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -74,7 +74,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI
 
     let proc_macros = if krate.is_proc_macro {
         db.proc_macros()
-            .for_crate(def_map.krate, db.syntax_context(tree_id.file_id()))
+            .for_crate(def_map.krate, db.syntax_context(tree_id.file_id(), krate.edition))
             .unwrap_or_default()
     } else {
         Default::default()
@@ -717,8 +717,8 @@ impl DefCollector<'_> {
                 }
             }
             None => {
-                for (name, def) in root_scope.macros() {
-                    self.def_map.macro_use_prelude.insert(name.clone(), (def, extern_crate));
+                for (name, it) in root_scope.macros() {
+                    self.def_map.macro_use_prelude.insert(name.clone(), (it.def, extern_crate));
                 }
             }
         }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
index 32c158415ba..318aee04f7b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
@@ -11,19 +11,19 @@ use triomphe::Arc;
 
 use crate::{db::DefDatabase, nameres::DefMap, test_db::TestDB};
 
-fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> {
+fn compute_crate_def_map(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> Arc<DefMap> {
     let db = TestDB::with_files(ra_fixture);
     let krate = db.fetch_test_crate();
     db.crate_def_map(krate)
 }
 
-fn render_crate_def_map(ra_fixture: &str) -> String {
+fn render_crate_def_map(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String {
     let db = TestDB::with_files(ra_fixture);
     let krate = db.fetch_test_crate();
     db.crate_def_map(krate).dump(&db)
 }
 
-fn check(ra_fixture: &str, expect: Expect) {
+fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let actual = render_crate_def_map(ra_fixture);
     expect.assert_eq(&actual);
 }
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 82da57a9bb2..0b9b6da8d51 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -166,6 +166,17 @@ impl Resolver {
         db: &dyn DefDatabase,
         path: &Path,
     ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> {
+        self.resolve_path_in_type_ns_with_prefix_info(db, path).map(
+            |(resolution, remaining_segments, import, _)| (resolution, remaining_segments, import),
+        )
+    }
+
+    pub fn resolve_path_in_type_ns_with_prefix_info(
+        &self,
+        db: &dyn DefDatabase,
+        path: &Path,
+    ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>, ResolvePathResultPrefixInfo)>
+    {
         let path = match path {
             Path::BarePath(mod_path) => mod_path,
             Path::Normal(it) => it.mod_path(),
@@ -181,7 +192,12 @@ impl Resolver {
                     | LangItemTarget::ImplDef(_)
                     | LangItemTarget::Static(_) => return None,
                 };
-                return Some((type_ns, seg.as_ref().map(|_| 1), None));
+                return Some((
+                    type_ns,
+                    seg.as_ref().map(|_| 1),
+                    None,
+                    ResolvePathResultPrefixInfo::default(),
+                ));
             }
         };
         let first_name = path.segments().first()?;
@@ -197,17 +213,32 @@ impl Resolver {
                 Scope::ExprScope(_) | Scope::MacroDefScope(_) => continue,
                 Scope::GenericParams { params, def } => {
                     if let Some(id) = params.find_type_by_name(first_name, *def) {
-                        return Some((TypeNs::GenericParam(id), remaining_idx(), None));
+                        return Some((
+                            TypeNs::GenericParam(id),
+                            remaining_idx(),
+                            None,
+                            ResolvePathResultPrefixInfo::default(),
+                        ));
                     }
                 }
                 &Scope::ImplDefScope(impl_) => {
                     if *first_name == sym::Self_.clone() {
-                        return Some((TypeNs::SelfType(impl_), remaining_idx(), None));
+                        return Some((
+                            TypeNs::SelfType(impl_),
+                            remaining_idx(),
+                            None,
+                            ResolvePathResultPrefixInfo::default(),
+                        ));
                     }
                 }
                 &Scope::AdtScope(adt) => {
                     if *first_name == sym::Self_.clone() {
-                        return Some((TypeNs::AdtSelfType(adt), remaining_idx(), None));
+                        return Some((
+                            TypeNs::AdtSelfType(adt),
+                            remaining_idx(),
+                            None,
+                            ResolvePathResultPrefixInfo::default(),
+                        ));
                     }
                 }
                 Scope::BlockScope(m) => {
@@ -220,18 +251,6 @@ impl Resolver {
         self.module_scope.resolve_path_in_type_ns(db, path)
     }
 
-    pub fn resolve_path_in_type_ns_fully_with_imports(
-        &self,
-        db: &dyn DefDatabase,
-        path: &Path,
-    ) -> Option<(TypeNs, Option<ImportOrExternCrate>)> {
-        let (res, unresolved, imp) = self.resolve_path_in_type_ns(db, path)?;
-        if unresolved.is_some() {
-            return None;
-        }
-        Some((res, imp))
-    }
-
     pub fn resolve_path_in_type_ns_fully(
         &self,
         db: &dyn DefDatabase,
@@ -324,7 +343,7 @@ impl Resolver {
 
         if n_segments <= 1 {
             let mut hygiene_info = if !hygiene_id.is_root() {
-                let ctx = db.lookup_intern_syntax_context(hygiene_id.0);
+                let ctx = hygiene_id.lookup(db);
                 ctx.outer_expn.map(|expansion| {
                     let expansion = db.lookup_intern_macro_call(expansion);
                     (ctx.parent, expansion.def)
@@ -986,11 +1005,12 @@ impl ModuleItemMap {
         &self,
         db: &dyn DefDatabase,
         path: &ModPath,
-    ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> {
-        let (module_def, idx, _) =
+    ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>, ResolvePathResultPrefixInfo)>
+    {
+        let (module_def, idx, prefix_info) =
             self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other);
         let (res, import) = to_type_ns(module_def)?;
-        Some((res, idx, import))
+        Some((res, idx, import, prefix_info))
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
index 4edb6835922..c4473e454a1 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
@@ -240,12 +240,12 @@ impl Visibility {
 
                 if a_ancestors.any(|m| m == mod_b.local_id) {
                     // B is above A
-                    return Some(Visibility::Module(mod_a, expl_b));
+                    return Some(Visibility::Module(mod_a, expl_a));
                 }
 
                 if b_ancestors.any(|m| m == mod_a.local_id) {
                     // A is above B
-                    return Some(Visibility::Module(mod_b, expl_a));
+                    return Some(Visibility::Module(mod_b, expl_b));
                 }
 
                 None
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs
index 4510a593af4..28b68121394 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs
@@ -4,7 +4,7 @@ use intern::sym;
 use itertools::{izip, Itertools};
 use parser::SyntaxKind;
 use rustc_hash::FxHashSet;
-use span::{MacroCallId, Span, SyntaxContextId};
+use span::{Edition, MacroCallId, Span, SyntaxContextId};
 use stdx::never;
 use syntax_bridge::DocCommentDesugarMode;
 use tracing::debug;
@@ -33,7 +33,7 @@ macro_rules! register_builtin {
         }
 
         impl BuiltinDeriveExpander {
-            pub fn expander(&self) -> fn(Span, &tt::TopSubtree) -> ExpandResult<tt::TopSubtree>  {
+            pub fn expander(&self) -> fn(&dyn ExpandDatabase, Span, &tt::TopSubtree) -> ExpandResult<tt::TopSubtree>  {
                 match *self {
                     $( BuiltinDeriveExpander::$trait => $expand, )*
                 }
@@ -58,8 +58,8 @@ impl BuiltinDeriveExpander {
         tt: &tt::TopSubtree,
         span: Span,
     ) -> ExpandResult<tt::TopSubtree> {
-        let span = span_with_def_site_ctxt(db, span, id);
-        self.expander()(span, tt)
+        let span = span_with_def_site_ctxt(db, span, id, Edition::CURRENT);
+        self.expander()(db, span, tt)
     }
 }
 
@@ -226,8 +226,12 @@ struct AdtParam {
 }
 
 // FIXME: This whole thing needs a refactor. Each derive requires its special values, and the result is a mess.
-fn parse_adt(tt: &tt::TopSubtree, call_site: Span) -> Result<BasicAdtInfo, ExpandError> {
-    let (adt, tm) = to_adt_syntax(tt, call_site)?;
+fn parse_adt(
+    db: &dyn ExpandDatabase,
+    tt: &tt::TopSubtree,
+    call_site: Span,
+) -> Result<BasicAdtInfo, ExpandError> {
+    let (adt, tm) = to_adt_syntax(db, tt, call_site)?;
     parse_adt_from_syntax(&adt, &tm, call_site)
 }
 
@@ -382,12 +386,14 @@ fn parse_adt_from_syntax(
 }
 
 fn to_adt_syntax(
+    db: &dyn ExpandDatabase,
     tt: &tt::TopSubtree,
     call_site: Span,
 ) -> Result<(ast::Adt, span::SpanMap<SyntaxContextId>), ExpandError> {
-    let (parsed, tm) = syntax_bridge::token_tree_to_syntax_node(
+    let (parsed, tm) = crate::db::token_tree_to_syntax_node(
+        db,
         tt,
-        syntax_bridge::TopEntryPoint::MacroItems,
+        crate::ExpandTo::Items,
         parser::Edition::CURRENT_FIXME,
     );
     let macro_items = ast::MacroItems::cast(parsed.syntax_node())
@@ -446,12 +452,13 @@ fn name_to_token(
 /// where B1, ..., BN are the bounds given by `bounds_paths`. Z is a phantom type, and
 /// therefore does not get bound by the derived trait.
 fn expand_simple_derive(
+    db: &dyn ExpandDatabase,
     invoc_span: Span,
     tt: &tt::TopSubtree,
     trait_path: tt::TopSubtree,
     make_trait_body: impl FnOnce(&BasicAdtInfo) -> tt::TopSubtree,
 ) -> ExpandResult<tt::TopSubtree> {
-    let info = match parse_adt(tt, invoc_span) {
+    let info = match parse_adt(db, tt, invoc_span) {
         Ok(info) => info,
         Err(e) => {
             return ExpandResult::new(
@@ -520,14 +527,22 @@ fn expand_simple_derive_with_parsed(
     }
 }
 
-fn copy_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> {
+fn copy_expand(
+    db: &dyn ExpandDatabase,
+    span: Span,
+    tt: &tt::TopSubtree,
+) -> ExpandResult<tt::TopSubtree> {
     let krate = dollar_crate(span);
-    expand_simple_derive(span, tt, quote! {span => #krate::marker::Copy }, |_| quote! {span =>})
+    expand_simple_derive(db, span, tt, quote! {span => #krate::marker::Copy }, |_| quote! {span =>})
 }
 
-fn clone_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> {
+fn clone_expand(
+    db: &dyn ExpandDatabase,
+    span: Span,
+    tt: &tt::TopSubtree,
+) -> ExpandResult<tt::TopSubtree> {
     let krate = dollar_crate(span);
-    expand_simple_derive(span, tt, quote! {span => #krate::clone::Clone }, |adt| {
+    expand_simple_derive(db, span, tt, quote! {span => #krate::clone::Clone }, |adt| {
         if matches!(adt.shape, AdtShape::Union) {
             let star = tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span };
             return quote! {span =>
@@ -576,9 +591,13 @@ fn and_and(span: Span) -> tt::TopSubtree {
     quote! {span => #and& }
 }
 
-fn default_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> {
+fn default_expand(
+    db: &dyn ExpandDatabase,
+    span: Span,
+    tt: &tt::TopSubtree,
+) -> ExpandResult<tt::TopSubtree> {
     let krate = &dollar_crate(span);
-    expand_simple_derive(span, tt, quote! {span => #krate::default::Default }, |adt| {
+    expand_simple_derive(db, span, tt, quote! {span => #krate::default::Default }, |adt| {
         let body = match &adt.shape {
             AdtShape::Struct(fields) => {
                 let name = &adt.name;
@@ -615,9 +634,13 @@ fn default_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtre
     })
 }
 
-fn debug_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> {
+fn debug_expand(
+    db: &dyn ExpandDatabase,
+    span: Span,
+    tt: &tt::TopSubtree,
+) -> ExpandResult<tt::TopSubtree> {
     let krate = &dollar_crate(span);
-    expand_simple_derive(span, tt, quote! {span => #krate::fmt::Debug }, |adt| {
+    expand_simple_derive(db, span, tt, quote! {span => #krate::fmt::Debug }, |adt| {
         let for_variant = |name: String, v: &VariantShape| match v {
             VariantShape::Struct(fields) => {
                 let for_fields = fields.iter().map(|it| {
@@ -687,9 +710,13 @@ fn debug_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree>
     })
 }
 
-fn hash_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> {
+fn hash_expand(
+    db: &dyn ExpandDatabase,
+    span: Span,
+    tt: &tt::TopSubtree,
+) -> ExpandResult<tt::TopSubtree> {
     let krate = &dollar_crate(span);
-    expand_simple_derive(span, tt, quote! {span => #krate::hash::Hash }, |adt| {
+    expand_simple_derive(db, span, tt, quote! {span => #krate::hash::Hash }, |adt| {
         if matches!(adt.shape, AdtShape::Union) {
             // FIXME: Return expand error here
             return quote! {span =>};
@@ -734,14 +761,22 @@ fn hash_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree>
     })
 }
 
-fn eq_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> {
+fn eq_expand(
+    db: &dyn ExpandDatabase,
+    span: Span,
+    tt: &tt::TopSubtree,
+) -> ExpandResult<tt::TopSubtree> {
     let krate = dollar_crate(span);
-    expand_simple_derive(span, tt, quote! {span => #krate::cmp::Eq }, |_| quote! {span =>})
+    expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::Eq }, |_| quote! {span =>})
 }
 
-fn partial_eq_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> {
+fn partial_eq_expand(
+    db: &dyn ExpandDatabase,
+    span: Span,
+    tt: &tt::TopSubtree,
+) -> ExpandResult<tt::TopSubtree> {
     let krate = dollar_crate(span);
-    expand_simple_derive(span, tt, quote! {span => #krate::cmp::PartialEq }, |adt| {
+    expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::PartialEq }, |adt| {
         if matches!(adt.shape, AdtShape::Union) {
             // FIXME: Return expand error here
             return quote! {span =>};
@@ -811,9 +846,13 @@ fn self_and_other_patterns(
     (self_patterns, other_patterns)
 }
 
-fn ord_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> {
+fn ord_expand(
+    db: &dyn ExpandDatabase,
+    span: Span,
+    tt: &tt::TopSubtree,
+) -> ExpandResult<tt::TopSubtree> {
     let krate = &dollar_crate(span);
-    expand_simple_derive(span, tt, quote! {span => #krate::cmp::Ord }, |adt| {
+    expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::Ord }, |adt| {
         fn compare(
             krate: &tt::Ident,
             left: tt::TopSubtree,
@@ -869,9 +908,13 @@ fn ord_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> {
     })
 }
 
-fn partial_ord_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> {
+fn partial_ord_expand(
+    db: &dyn ExpandDatabase,
+    span: Span,
+    tt: &tt::TopSubtree,
+) -> ExpandResult<tt::TopSubtree> {
     let krate = &dollar_crate(span);
-    expand_simple_derive(span, tt, quote! {span => #krate::cmp::PartialOrd }, |adt| {
+    expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::PartialOrd }, |adt| {
         fn compare(
             krate: &tt::Ident,
             left: tt::TopSubtree,
@@ -932,8 +975,12 @@ fn partial_ord_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSu
     })
 }
 
-fn coerce_pointee_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> {
-    let (adt, _span_map) = match to_adt_syntax(tt, span) {
+fn coerce_pointee_expand(
+    db: &dyn ExpandDatabase,
+    span: Span,
+    tt: &tt::TopSubtree,
+) -> ExpandResult<tt::TopSubtree> {
+    let (adt, _span_map) = match to_adt_syntax(db, tt, span) {
         Ok(it) => it,
         Err(err) => {
             return ExpandResult::new(tt::TopSubtree::empty(tt::DelimSpan::from_single(span)), err);
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
index 5b06de98757..310ddaaf9e9 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
@@ -69,7 +69,7 @@ impl BuiltinFnLikeExpander {
         tt: &tt::TopSubtree,
         span: Span,
     ) -> ExpandResult<tt::TopSubtree> {
-        let span = span_with_def_site_ctxt(db, span, id);
+        let span = span_with_def_site_ctxt(db, span, id, Edition::CURRENT);
         self.expander()(db, id, tt, span)
     }
 
@@ -86,7 +86,7 @@ impl EagerExpander {
         tt: &tt::TopSubtree,
         span: Span,
     ) -> ExpandResult<tt::TopSubtree> {
-        let span = span_with_def_site_ctxt(db, span, id);
+        let span = span_with_def_site_ctxt(db, span, id, Edition::CURRENT);
         self.expander()(db, id, tt, span)
     }
 
@@ -221,7 +221,7 @@ fn assert_expand(
     tt: &tt::TopSubtree,
     span: Span,
 ) -> ExpandResult<tt::TopSubtree> {
-    let call_site_span = span_with_call_site_ctxt(db, span, id);
+    let call_site_span = span_with_call_site_ctxt(db, span, id, Edition::CURRENT);
 
     let mut iter = tt.iter();
 
@@ -342,7 +342,7 @@ fn panic_expand(
     span: Span,
 ) -> ExpandResult<tt::TopSubtree> {
     let dollar_crate = dollar_crate(span);
-    let call_site_span = span_with_call_site_ctxt(db, span, id);
+    let call_site_span = span_with_call_site_ctxt(db, span, id, Edition::CURRENT);
 
     let mac = if use_panic_2021(db, call_site_span) {
         sym::panic_2021.clone()
@@ -373,7 +373,7 @@ fn unreachable_expand(
     span: Span,
 ) -> ExpandResult<tt::TopSubtree> {
     let dollar_crate = dollar_crate(span);
-    let call_site_span = span_with_call_site_ctxt(db, span, id);
+    let call_site_span = span_with_call_site_ctxt(db, span, id, Edition::CURRENT);
 
     let mac = if use_panic_2021(db, call_site_span) {
         sym::unreachable_2021.clone()
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs
index 6c1abc26203..9b637fc7684 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs
@@ -102,6 +102,7 @@ macro_rules! quote_impl__ {
     ($span:ident $builder:ident # ) => {$crate::builtin::quote::__quote!(@PUNCT($span $builder) '#')};
     ($span:ident $builder:ident $ ) => {$crate::builtin::quote::__quote!(@PUNCT($span $builder) '$')};
     ($span:ident $builder:ident * ) => {$crate::builtin::quote::__quote!(@PUNCT($span $builder) '*')};
+    ($span:ident $builder:ident = ) => {$crate::builtin::quote::__quote!(@PUNCT($span $builder) '=')};
 
     ($span:ident $builder:ident $first:tt $($tail:tt)+ ) => {{
         $crate::builtin::quote::__quote!($span $builder $first);
@@ -225,7 +226,7 @@ mod tests {
     use ::tt::IdentIsRaw;
     use expect_test::expect;
     use intern::Symbol;
-    use span::{SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID};
+    use span::{Edition, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID};
     use syntax::{TextRange, TextSize};
 
     use super::quote;
@@ -239,7 +240,7 @@ mod tests {
             ),
             ast_id: ROOT_ERASED_FILE_AST_ID,
         },
-        ctx: SyntaxContextId::ROOT,
+        ctx: SyntaxContextId::root(Edition::CURRENT),
     };
 
     #[test]
@@ -276,8 +277,8 @@ mod tests {
         assert_eq!(quoted.to_string(), "hello");
         let t = format!("{quoted:#?}");
         expect![[r#"
-            SUBTREE $$ 937550:0@0..0#0 937550:0@0..0#0
-              IDENT   hello 937550:0@0..0#0"#]]
+            SUBTREE $$ 937550:0@0..0#2 937550:0@0..0#2
+              IDENT   hello 937550:0@0..0#2"#]]
         .assert_eq(&t);
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
index f4e80ef9e26..b7804f888ae 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
@@ -5,7 +5,7 @@ use either::Either;
 use limit::Limit;
 use mbe::MatchedArmIndex;
 use rustc_hash::FxHashSet;
-use span::{AstIdMap, EditionedFileId, Span, SyntaxContextData, SyntaxContextId};
+use span::{AstIdMap, Edition, EditionedFileId, Span, SyntaxContextData, SyntaxContextId};
 use syntax::{ast, AstNode, Parse, SyntaxElement, SyntaxError, SyntaxNode, SyntaxToken, T};
 use syntax_bridge::{syntax_node_to_token_tree, DocCommentDesugarMode};
 use triomphe::Arc;
@@ -136,12 +136,12 @@ pub trait ExpandDatabase: SourceDatabase {
         macro_call: MacroCallId,
     ) -> Option<Arc<ExpandResult<Arc<[SyntaxError]>>>>;
     #[ra_salsa::transparent]
-    fn syntax_context(&self, file: HirFileId) -> SyntaxContextId;
+    fn syntax_context(&self, file: HirFileId, edition: Edition) -> SyntaxContextId;
 }
 
-fn syntax_context(db: &dyn ExpandDatabase, file: HirFileId) -> SyntaxContextId {
+fn syntax_context(db: &dyn ExpandDatabase, file: HirFileId, edition: Edition) -> SyntaxContextId {
     match file.repr() {
-        HirFileIdRepr::FileId(_) => SyntaxContextId::ROOT,
+        HirFileIdRepr::FileId(_) => SyntaxContextId::root(edition),
         HirFileIdRepr::MacroFile(m) => {
             db.macro_arg_considering_derives(m.macro_call_id, &m.macro_call_id.lookup(db).kind)
                 .2
@@ -273,9 +273,9 @@ pub fn expand_speculative(
                 loc.krate,
                 &tt,
                 attr_arg.as_ref(),
-                span_with_def_site_ctxt(db, span, actual_macro_call),
-                span_with_call_site_ctxt(db, span, actual_macro_call),
-                span_with_mixed_site_ctxt(db, span, actual_macro_call),
+                span_with_def_site_ctxt(db, span, actual_macro_call, loc.def.edition),
+                span_with_call_site_ctxt(db, span, actual_macro_call, loc.def.edition),
+                span_with_mixed_site_ctxt(db, span, actual_macro_call, loc.def.edition),
             )
         }
         MacroDefKind::BuiltInAttr(_, it) if it.is_derive() => {
@@ -300,7 +300,7 @@ pub fn expand_speculative(
 
     fixup::reverse_fixups(&mut speculative_expansion.value, &undo_info);
     let (node, rev_tmap) =
-        token_tree_to_syntax_node(&speculative_expansion.value, expand_to, loc.def.edition);
+        token_tree_to_syntax_node(db, &speculative_expansion.value, expand_to, loc.def.edition);
 
     let syntax_node = node.syntax_node();
     let token = rev_tmap
@@ -346,6 +346,7 @@ fn parse_macro_expansion(
         macro_expand(db, macro_file.macro_call_id, loc);
 
     let (parse, mut rev_token_map) = token_tree_to_syntax_node(
+        db,
         match &tt {
             CowArc::Arc(it) => it,
             CowArc::Owned(it) => it,
@@ -699,9 +700,9 @@ fn expand_proc_macro(
             loc.krate,
             &macro_arg,
             attr_arg,
-            span_with_def_site_ctxt(db, span, id),
-            span_with_call_site_ctxt(db, span, id),
-            span_with_mixed_site_ctxt(db, span, id),
+            span_with_def_site_ctxt(db, span, id, loc.def.edition),
+            span_with_call_site_ctxt(db, span, id, loc.def.edition),
+            span_with_mixed_site_ctxt(db, span, id, loc.def.edition),
         )
     };
 
@@ -715,7 +716,8 @@ fn expand_proc_macro(
     ExpandResult { value: Arc::new(tt), err }
 }
 
-fn token_tree_to_syntax_node(
+pub(crate) fn token_tree_to_syntax_node(
+    db: &dyn ExpandDatabase,
     tt: &tt::TopSubtree,
     expand_to: ExpandTo,
     edition: parser::Edition,
@@ -727,7 +729,12 @@ fn token_tree_to_syntax_node(
         ExpandTo::Type => syntax_bridge::TopEntryPoint::Type,
         ExpandTo::Expr => syntax_bridge::TopEntryPoint::Expr,
     };
-    syntax_bridge::token_tree_to_syntax_node(tt, entry_point, edition)
+    syntax_bridge::token_tree_to_syntax_node(
+        tt,
+        entry_point,
+        &mut |ctx| ctx.lookup(db).edition,
+        edition,
+    )
 }
 
 fn check_tt_count(tt: &tt::TopSubtree) -> Result<(), ExpandResult<()>> {
@@ -751,5 +758,7 @@ fn check_tt_count(tt: &tt::TopSubtree) -> Result<(), ExpandResult<()>> {
 }
 
 fn setup_syntax_context_root(db: &dyn ExpandDatabase) {
-    db.intern_syntax_context(SyntaxContextData::root());
+    for edition in Edition::iter() {
+        db.intern_syntax_context(SyntaxContextData::root(edition));
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs
index d1c39f32ca3..fef77acb7bb 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs
@@ -2,7 +2,7 @@
 
 use base_db::CrateId;
 use intern::sym;
-use span::{Edition, MacroCallId, Span, SyntaxContextId};
+use span::{Edition, HirFileIdRepr, MacroCallId, Span, SyntaxContextId};
 use stdx::TupleExt;
 use syntax::{ast, AstNode};
 use syntax_bridge::DocCommentDesugarMode;
@@ -20,6 +20,7 @@ use crate::{
 pub struct DeclarativeMacroExpander {
     pub mac: mbe::DeclarativeMacro,
     pub transparency: Transparency,
+    edition: Edition,
 }
 
 impl DeclarativeMacroExpander {
@@ -40,7 +41,7 @@ impl DeclarativeMacroExpander {
                 .mac
                 .expand(
                     &tt,
-                    |s| s.ctx = apply_mark(db, s.ctx, call_id, self.transparency),
+                    |s| s.ctx = apply_mark(db, s.ctx, call_id, self.transparency, self.edition),
                     span,
                     loc.def.edition,
                 )
@@ -159,6 +160,10 @@ impl DeclarativeMacroExpander {
                 transparency(&macro_def).unwrap_or(Transparency::Opaque),
             ),
         };
-        Arc::new(DeclarativeMacroExpander { mac, transparency })
+        let edition = ctx_edition(match id.file_id.repr() {
+            HirFileIdRepr::MacroFile(macro_file) => macro_file.macro_call_id.lookup(db).ctxt,
+            HirFileIdRepr::FileId(file) => SyntaxContextId::root(file.edition()),
+        });
+        Arc::new(DeclarativeMacroExpander { mac, transparency, edition })
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs
index 8c04d054029..13ddb0d4acc 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs
@@ -380,14 +380,14 @@ impl InFile<TextRange> {
     ) -> (FileRange, SyntaxContextId) {
         match self.file_id.repr() {
             HirFileIdRepr::FileId(file_id) => {
-                (FileRange { file_id, range: self.value }, SyntaxContextId::ROOT)
+                (FileRange { file_id, range: self.value }, SyntaxContextId::root(file_id.edition()))
             }
             HirFileIdRepr::MacroFile(mac_file) => {
                 match map_node_range_up(db, &db.expansion_span_map(mac_file), self.value) {
                     Some(it) => it,
                     None => {
                         let loc = db.lookup_intern_macro_call(mac_file.macro_call_id);
-                        (loc.kind.original_call_range(db), SyntaxContextId::ROOT)
+                        (loc.kind.original_call_range(db), SyntaxContextId::root(loc.def.edition))
                     }
                 }
             }
@@ -432,9 +432,10 @@ impl InFile<TextRange> {
         db: &dyn db::ExpandDatabase,
     ) -> Option<(FileRange, SyntaxContextId)> {
         match self.file_id.repr() {
-            HirFileIdRepr::FileId(file_id) => {
-                Some((FileRange { file_id, range: self.value }, SyntaxContextId::ROOT))
-            }
+            HirFileIdRepr::FileId(file_id) => Some((
+                FileRange { file_id, range: self.value },
+                SyntaxContextId::root(file_id.edition()),
+            )),
             HirFileIdRepr::MacroFile(mac_file) => {
                 map_node_range_up(db, &db.expansion_span_map(mac_file), self.value)
             }
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 3d2d52a0afe..eb430177390 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
@@ -380,7 +380,7 @@ pub(crate) fn reverse_fixups(tt: &mut TopSubtree, undo_info: &SyntaxFixupUndoInf
         let span = |file_id| Span {
             range: TextRange::empty(TextSize::new(0)),
             anchor: SpanAnchor { file_id, ast_id: ROOT_ERASED_FILE_AST_ID },
-            ctx: SyntaxContextId::ROOT,
+            ctx: SyntaxContextId::root(span::Edition::Edition2015),
         };
         delimiter.open = span(delimiter.open.anchor.file_id);
         delimiter.close = span(delimiter.close.anchor.file_id);
@@ -441,8 +441,8 @@ fn transform_tt<'a, 'b>(
                 };
                 let len_diff = replacement.len() as i64 - old_len as i64;
                 tt.splice(i..i + old_len, replacement.flat_tokens().iter().cloned());
-                // `+1` for the loop.
-                i = i.checked_add_signed(len_diff as isize + 1).unwrap();
+                // Skip the newly inserted replacement, we don't want to visit it.
+                i += replacement.len();
 
                 for &subtree_idx in &subtrees_stack {
                     let tt::TokenTree::Subtree(subtree) = &mut tt[subtree_idx] else {
@@ -532,7 +532,7 @@ mod tests {
     }
 
     #[track_caller]
-    fn check(ra_fixture: &str, mut expect: Expect) {
+    fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, mut expect: Expect) {
         let parsed = syntax::SourceFile::parse(ra_fixture, span::Edition::CURRENT);
         let span_map = SpanMap::RealSpanMap(Arc::new(RealSpanMap::absolute(EditionedFileId::new(
             FileId::from_raw(0),
@@ -562,6 +562,7 @@ mod tests {
         let (parse, _) = syntax_bridge::token_tree_to_syntax_node(
             &tt,
             syntax_bridge::TopEntryPoint::MacroItems,
+            &mut |_| parser::Edition::CURRENT,
             parser::Edition::CURRENT,
         );
         assert!(
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
index f48de807c28..fe05af0ac9d 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
@@ -24,26 +24,37 @@
 
 use std::iter;
 
-use span::{MacroCallId, Span, SyntaxContextData, SyntaxContextId};
+use span::{Edition, MacroCallId, Span, SyntaxContextData, SyntaxContextId};
 
 use crate::db::{ExpandDatabase, InternSyntaxContextQuery};
 
 pub use span::Transparency;
 
-pub fn span_with_def_site_ctxt(db: &dyn ExpandDatabase, span: Span, expn_id: MacroCallId) -> Span {
-    span_with_ctxt_from_mark(db, span, expn_id, Transparency::Opaque)
+pub fn span_with_def_site_ctxt(
+    db: &dyn ExpandDatabase,
+    span: Span,
+    expn_id: MacroCallId,
+    edition: Edition,
+) -> Span {
+    span_with_ctxt_from_mark(db, span, expn_id, Transparency::Opaque, edition)
 }
 
-pub fn span_with_call_site_ctxt(db: &dyn ExpandDatabase, span: Span, expn_id: MacroCallId) -> Span {
-    span_with_ctxt_from_mark(db, span, expn_id, Transparency::Transparent)
+pub fn span_with_call_site_ctxt(
+    db: &dyn ExpandDatabase,
+    span: Span,
+    expn_id: MacroCallId,
+    edition: Edition,
+) -> Span {
+    span_with_ctxt_from_mark(db, span, expn_id, Transparency::Transparent, edition)
 }
 
 pub fn span_with_mixed_site_ctxt(
     db: &dyn ExpandDatabase,
     span: Span,
     expn_id: MacroCallId,
+    edition: Edition,
 ) -> Span {
-    span_with_ctxt_from_mark(db, span, expn_id, Transparency::SemiTransparent)
+    span_with_ctxt_from_mark(db, span, expn_id, Transparency::SemiTransparent, edition)
 }
 
 fn span_with_ctxt_from_mark(
@@ -51,8 +62,12 @@ fn span_with_ctxt_from_mark(
     span: Span,
     expn_id: MacroCallId,
     transparency: Transparency,
+    edition: Edition,
 ) -> Span {
-    Span { ctx: apply_mark(db, SyntaxContextId::ROOT, expn_id, transparency), ..span }
+    Span {
+        ctx: apply_mark(db, SyntaxContextId::root(edition), expn_id, transparency, edition),
+        ..span
+    }
 }
 
 pub(super) fn apply_mark(
@@ -60,9 +75,10 @@ pub(super) fn apply_mark(
     ctxt: SyntaxContextId,
     call_id: MacroCallId,
     transparency: Transparency,
+    edition: Edition,
 ) -> SyntaxContextId {
     if transparency == Transparency::Opaque {
-        return apply_mark_internal(db, ctxt, call_id, transparency);
+        return apply_mark_internal(db, ctxt, call_id, transparency, edition);
     }
 
     let call_site_ctxt = db.lookup_intern_macro_call(call_id).ctxt;
@@ -73,7 +89,7 @@ pub(super) fn apply_mark(
     };
 
     if call_site_ctxt.is_root() {
-        return apply_mark_internal(db, ctxt, call_id, transparency);
+        return apply_mark_internal(db, ctxt, call_id, transparency, edition);
     }
 
     // Otherwise, `expn_id` is a macros 1.0 definition and the call site is in a
@@ -86,9 +102,9 @@ pub(super) fn apply_mark(
     //
     // See the example at `test/ui/hygiene/legacy_interaction.rs`.
     for (call_id, transparency) in ctxt.marks(db) {
-        call_site_ctxt = apply_mark_internal(db, call_site_ctxt, call_id, transparency);
+        call_site_ctxt = apply_mark_internal(db, call_site_ctxt, call_id, transparency, edition);
     }
-    apply_mark_internal(db, call_site_ctxt, call_id, transparency)
+    apply_mark_internal(db, call_site_ctxt, call_id, transparency, edition)
 }
 
 fn apply_mark_internal(
@@ -96,6 +112,7 @@ fn apply_mark_internal(
     ctxt: SyntaxContextId,
     call_id: MacroCallId,
     transparency: Transparency,
+    edition: Edition,
 ) -> SyntaxContextId {
     use base_db::ra_salsa;
 
@@ -108,13 +125,14 @@ fn apply_mark_internal(
     if transparency >= Transparency::Opaque {
         let parent = opaque;
         opaque = ra_salsa::plumbing::get_query_table::<InternSyntaxContextQuery>(db).get_or_insert(
-            (parent, call_id, transparency),
+            (parent, call_id, transparency, edition),
             |new_opaque| SyntaxContextData {
                 outer_expn: call_id,
                 outer_transparency: transparency,
                 parent,
                 opaque: new_opaque,
                 opaque_and_semitransparent: new_opaque,
+                edition,
             },
         );
     }
@@ -123,13 +141,14 @@ fn apply_mark_internal(
         let parent = opaque_and_semitransparent;
         opaque_and_semitransparent =
             ra_salsa::plumbing::get_query_table::<InternSyntaxContextQuery>(db).get_or_insert(
-                (parent, call_id, transparency),
+                (parent, call_id, transparency, edition),
                 |new_opaque_and_semitransparent| SyntaxContextData {
                     outer_expn: call_id,
                     outer_transparency: transparency,
                     parent,
                     opaque,
                     opaque_and_semitransparent: new_opaque_and_semitransparent,
+                    edition,
                 },
             );
     }
@@ -141,6 +160,7 @@ fn apply_mark_internal(
         parent,
         opaque,
         opaque_and_semitransparent,
+        edition,
     })
 }
 
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 a0c4c125db4..2c664029f61 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
@@ -188,6 +188,8 @@ impl fmt::Display for RenderedExpandError {
 
 impl RenderedExpandError {
     const GENERAL_KIND: &str = "macro-error";
+    const DISABLED: &str = "proc-macro-disabled";
+    const ATTR_EXP_DISABLED: &str = "attribute-expansion-disabled";
 }
 
 impl ExpandErrorKind {
@@ -196,12 +198,12 @@ impl ExpandErrorKind {
             ExpandErrorKind::ProcMacroAttrExpansionDisabled => RenderedExpandError {
                 message: "procedural attribute macro expansion is disabled".to_owned(),
                 error: false,
-                kind: "proc-macros-disabled",
+                kind: RenderedExpandError::ATTR_EXP_DISABLED,
             },
             ExpandErrorKind::MacroDisabled => RenderedExpandError {
                 message: "proc-macro is explicitly disabled".to_owned(),
                 error: false,
-                kind: "proc-macro-disabled",
+                kind: RenderedExpandError::DISABLED,
             },
             &ExpandErrorKind::MissingProcMacroExpander(def_crate) => {
                 match db.proc_macros().get_error_for_crate(def_crate) {
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 7ecf5219873..89eae862bd9 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
@@ -273,10 +273,9 @@ fn convert_path(
                 res
             }
         }
-        ast::PathSegmentKind::SelfTypeKw => ModPath::from_segments(
-            PathKind::Plain,
-            Some(Name::new_symbol(sym::Self_.clone(), SyntaxContextId::ROOT)),
-        ),
+        ast::PathSegmentKind::SelfTypeKw => {
+            ModPath::from_segments(PathKind::Plain, Some(Name::new_symbol_root(sym::Self_.clone())))
+        }
         ast::PathSegmentKind::CrateKw => ModPath::from_segments(PathKind::Crate, iter::empty()),
         ast::PathSegmentKind::SelfKw => handle_super_kw(0)?,
         ast::PathSegmentKind::SuperKw => handle_super_kw(1)?,
@@ -399,6 +398,9 @@ macro_rules! __known_path {
     (core::fmt::Debug) => {};
     (std::fmt::format) => {};
     (core::ops::Try) => {};
+    (core::convert::From) => {};
+    (core::convert::TryFrom) => {};
+    (core::str::FromStr) => {};
     ($path:path) => {
         compile_error!("Please register your known path in the path module")
     };
@@ -415,3 +417,14 @@ macro_rules! __path {
 }
 
 pub use crate::__path as path;
+
+#[macro_export]
+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()),)*
+        ])
+    });
+}
+
+pub use crate::__tool_path as tool_path;
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
index 267d5458333..cc53d2e34aa 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
@@ -11,7 +11,7 @@ use syntax::utils::is_raw_identifier;
 /// and declarations. In theory, names should also carry hygiene info, but we are
 /// not there yet!
 ///
-/// Note that the rawness (`r#`) of names does not depend on whether they are written raw.
+/// Note that the rawness (`r#`) of names is not preserved. Names are always stored without a `r#` prefix.
 /// This is because we want to show (in completions etc.) names as raw depending on the needs
 /// of the current crate, for example if it is edition 2021 complete `gen` even if the defining
 /// crate is in edition 2024 and wrote `r#gen`, and the opposite holds as well.
@@ -77,20 +77,49 @@ impl Name {
     /// Hopefully, this should allow us to integrate hygiene cleaner in the
     /// future, and to switch to interned representation of names.
     fn new_text(text: &str) -> Name {
+        debug_assert!(!text.starts_with("r#"));
         Name { symbol: Symbol::intern(text), ctx: () }
     }
 
-    pub fn new(text: &str, ctx: SyntaxContextId) -> Name {
+    pub fn new(text: &str, mut ctx: SyntaxContextId) -> Name {
+        // For comparisons etc. we remove the edition, because sometimes we search for some `Name`
+        // and we don't know which edition it came from.
+        // Can't do that for all `SyntaxContextId`s because it breaks Salsa.
+        ctx.remove_root_edition();
         _ = ctx;
         Self::new_text(text)
     }
 
+    pub fn new_root(text: &str) -> Name {
+        // The edition doesn't matter for hygiene.
+        Self::new(text.trim_start_matches("r#"), SyntaxContextId::root(Edition::Edition2015))
+    }
+
     pub fn new_tuple_field(idx: usize) -> Name {
-        Name { symbol: Symbol::intern(&idx.to_string()), ctx: () }
+        let symbol = match idx {
+            0 => sym::INTEGER_0.clone(),
+            1 => sym::INTEGER_1.clone(),
+            2 => sym::INTEGER_2.clone(),
+            3 => sym::INTEGER_3.clone(),
+            4 => sym::INTEGER_4.clone(),
+            5 => sym::INTEGER_5.clone(),
+            6 => sym::INTEGER_6.clone(),
+            7 => sym::INTEGER_7.clone(),
+            8 => sym::INTEGER_8.clone(),
+            9 => sym::INTEGER_9.clone(),
+            10 => sym::INTEGER_10.clone(),
+            11 => sym::INTEGER_11.clone(),
+            12 => sym::INTEGER_12.clone(),
+            13 => sym::INTEGER_13.clone(),
+            14 => sym::INTEGER_14.clone(),
+            15 => sym::INTEGER_15.clone(),
+            _ => Symbol::intern(&idx.to_string()),
+        };
+        Name { symbol, ctx: () }
     }
 
     pub fn new_lifetime(lt: &ast::Lifetime) -> Name {
-        Name { symbol: Symbol::intern(lt.text().as_str()), ctx: () }
+        Self::new_text(lt.text().as_str().trim_start_matches("r#"))
     }
 
     /// Resolve a name from the text of token.
@@ -133,15 +162,18 @@ impl Name {
     }
 
     /// Returns the text this name represents if it isn't a tuple field.
+    ///
+    /// Do not use this for user-facing text, use `display` instead to handle editions properly.
     pub fn as_str(&self) -> &str {
         self.symbol.as_str()
     }
 
+    // FIXME: Remove this
     pub fn unescaped(&self) -> UnescapedName<'_> {
         UnescapedName(self)
     }
 
-    pub fn is_escaped(&self, edition: Edition) -> bool {
+    pub fn needs_escape(&self, edition: Edition) -> bool {
         is_raw_identifier(self.symbol.as_str(), edition)
     }
 
@@ -164,16 +196,19 @@ impl Name {
         &self.symbol
     }
 
-    pub const fn new_symbol(symbol: Symbol, ctx: SyntaxContextId) -> Self {
+    pub fn new_symbol(symbol: Symbol, ctx: SyntaxContextId) -> Self {
+        debug_assert!(!symbol.as_str().starts_with("r#"));
         _ = ctx;
         Self { symbol, ctx: () }
     }
 
     // FIXME: This needs to go once we have hygiene
-    pub const fn new_symbol_root(sym: Symbol) -> Self {
+    pub fn new_symbol_root(sym: Symbol) -> Self {
+        debug_assert!(!sym.as_str().starts_with("r#"));
         Self { symbol: sym, ctx: () }
     }
 
+    // FIXME: Remove this
     #[inline]
     pub fn eq_ident(&self, ident: &str) -> bool {
         self.as_str() == ident.trim_start_matches("r#")
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 9f01f1eb259..c8ff6cba3dd 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
@@ -856,7 +856,7 @@ fn impl_def_datum(
     let associated_ty_value_ids = impl_data
         .items
         .iter()
-        .filter_map(|item| match item {
+        .filter_map(|(_, item)| match item {
             AssocItemId::TypeAliasId(type_alias) => Some(*type_alias),
             _ => None,
         })
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 0a8bfaa70f8..2d7d4cacd2c 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
@@ -31,7 +31,10 @@ fn simplify(e: ConstEvalError) -> ConstEvalError {
 }
 
 #[track_caller]
-fn check_fail(ra_fixture: &str, error: impl FnOnce(ConstEvalError) -> bool) {
+fn check_fail(
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    error: impl FnOnce(ConstEvalError) -> bool,
+) {
     let (db, file_id) = TestDB::with_single_file(ra_fixture);
     match eval_goal(&db, file_id) {
         Ok(_) => panic!("Expected fail, but it succeeded"),
@@ -42,7 +45,7 @@ fn check_fail(ra_fixture: &str, error: impl FnOnce(ConstEvalError) -> bool) {
 }
 
 #[track_caller]
-fn check_number(ra_fixture: &str, answer: i128) {
+fn check_number(#[rust_analyzer::rust_fixture] ra_fixture: &str, answer: i128) {
     check_answer(ra_fixture, |b, _| {
         assert_eq!(
             b,
@@ -54,7 +57,7 @@ fn check_number(ra_fixture: &str, answer: i128) {
 }
 
 #[track_caller]
-fn check_str(ra_fixture: &str, answer: &str) {
+fn check_str(#[rust_analyzer::rust_fixture] ra_fixture: &str, answer: &str) {
     check_answer(ra_fixture, |b, mm| {
         let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap());
         let size = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap());
@@ -71,7 +74,10 @@ fn check_str(ra_fixture: &str, answer: &str) {
 }
 
 #[track_caller]
-fn check_answer(ra_fixture: &str, check: impl FnOnce(&[u8], &MemoryMap)) {
+fn check_answer(
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    check: impl FnOnce(&[u8], &MemoryMap),
+) {
     let (db, file_ids) = TestDB::with_many_files(ra_fixture);
     let file_id = *file_ids.last().unwrap();
     let r = match eval_goal(&db, file_id) {
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 a4e052a0362..3545bf76776 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -471,10 +471,55 @@ impl HirDisplay for ProjectionTy {
         if f.should_truncate() {
             return write!(f, "{TYPE_HINT_TRUNCATION}");
         }
-
         let trait_ref = self.trait_ref(f.db);
+        let self_ty = trait_ref.self_type_parameter(Interner);
+
+        // 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 let TyKind::Placeholder(idx) = self_ty.kind(Interner) {
+                let db = f.db;
+                let id = from_placeholder_idx(db, *idx);
+                let generics = generics(db.upcast(), id.parent);
+
+                let substs = generics.placeholder_subst(db);
+                let bounds = db
+                    .generic_predicates(id.parent)
+                    .iter()
+                    .map(|pred| pred.clone().substitute(Interner, &substs))
+                    .filter(|wc| match wc.skip_binders() {
+                        WhereClause::Implemented(tr) => {
+                            match tr.self_type_parameter(Interner).kind(Interner) {
+                                TyKind::Alias(AliasTy::Projection(proj)) => proj == self,
+                                _ => false,
+                            }
+                        }
+                        WhereClause::TypeOutlives(t) => match t.ty.kind(Interner) {
+                            TyKind::Alias(AliasTy::Projection(proj)) => proj == self,
+                            _ => false,
+                        },
+                        // We shouldn't be here if these exist
+                        WhereClause::AliasEq(_) => false,
+                        WhereClause::LifetimeOutlives(_) => false,
+                    })
+                    .collect::<Vec<_>>();
+                if !bounds.is_empty() {
+                    return write_bounds_like_dyn_trait_with_prefix(
+                        f,
+                        "impl",
+                        Either::Left(
+                            &TyKind::Alias(AliasTy::Projection(self.clone())).intern(Interner),
+                        ),
+                        &bounds,
+                        SizedByDefault::NotSized,
+                    );
+                };
+            }
+        }
+
         write!(f, "<")?;
-        trait_ref.self_type_parameter(Interner).hir_fmt(f)?;
+        self_ty.hir_fmt(f)?;
         write!(f, " as ")?;
         trait_ref.hir_fmt(f)?;
         write!(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs
index 8a56bd28b59..3060b610bb6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs
@@ -26,7 +26,7 @@ enum DynCompatibilityViolationKind {
 }
 
 fn check_dyn_compatibility<'a>(
-    ra_fixture: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
     expected: impl IntoIterator<Item = (&'a str, Vec<DynCompatibilityViolationKind>)>,
 ) {
     let mut expected: FxHashMap<_, _> =
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 66159ddce2b..4d3896660b4 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
@@ -25,7 +25,10 @@ fn current_machine_data_layout() -> String {
     .unwrap()
 }
 
-fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutError> {
+fn eval_goal(
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    minicore: &str,
+) -> Result<Arc<Layout>, LayoutError> {
     let target_data_layout = current_machine_data_layout();
     let ra_fixture = format!(
         "//- target_data_layout: {target_data_layout}\n{minicore}//- /main.rs crate:test\n{ra_fixture}",
@@ -81,7 +84,10 @@ fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
 }
 
 /// A version of `eval_goal` for types that can not be expressed in ADTs, like closures and `impl Trait`
-fn eval_expr(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutError> {
+fn eval_expr(
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    minicore: &str,
+) -> Result<Arc<Layout>, LayoutError> {
     let target_data_layout = current_machine_data_layout();
     let ra_fixture = format!(
         "//- target_data_layout: {target_data_layout}\n{minicore}//- /main.rs crate:test\nfn main(){{let goal = {{{ra_fixture}}};}}",
@@ -114,21 +120,31 @@ fn eval_expr(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
 }
 
 #[track_caller]
-fn check_size_and_align(ra_fixture: &str, minicore: &str, size: u64, align: u64) {
+fn check_size_and_align(
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    minicore: &str,
+    size: u64,
+    align: u64,
+) {
     let l = eval_goal(ra_fixture, minicore).unwrap();
     assert_eq!(l.size.bytes(), size, "size mismatch");
     assert_eq!(l.align.abi.bytes(), align, "align mismatch");
 }
 
 #[track_caller]
-fn check_size_and_align_expr(ra_fixture: &str, minicore: &str, size: u64, align: u64) {
+fn check_size_and_align_expr(
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    minicore: &str,
+    size: u64,
+    align: u64,
+) {
     let l = eval_expr(ra_fixture, minicore).unwrap();
     assert_eq!(l.size.bytes(), size, "size mismatch");
     assert_eq!(l.align.abi.bytes(), align, "align mismatch");
 }
 
 #[track_caller]
-fn check_fail(ra_fixture: &str, e: LayoutError) {
+fn check_fail(#[rust_analyzer::rust_fixture] ra_fixture: &str, e: LayoutError) {
     let r = eval_goal(ra_fixture, "");
     assert_eq!(r, Err(e));
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index 24f67fd6602..432b8f4d94e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -761,8 +761,8 @@ impl<'a> TyLoweringContext<'a> {
         path: &Path,
         on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic),
     ) -> Option<(TypeNs, Option<usize>)> {
-        let (resolution, remaining_index, _) =
-            self.resolver.resolve_path_in_type_ns(self.db.upcast(), path)?;
+        let (resolution, remaining_index, _, prefix_info) =
+            self.resolver.resolve_path_in_type_ns_with_prefix_info(self.db.upcast(), path)?;
         let segments = path.segments();
 
         match path {
@@ -771,13 +771,12 @@ impl<'a> TyLoweringContext<'a> {
             _ => return Some((resolution, remaining_index)),
         };
 
-        let (module_segments, resolved_segment_idx, resolved_segment) = match remaining_index {
-            None => (
-                segments.strip_last(),
-                segments.len() - 1,
-                segments.last().expect("resolved path has at least one element"),
-            ),
-            Some(i) => (segments.take(i - 1), i - 1, segments.get(i - 1).unwrap()),
+        let (module_segments, resolved_segment_idx, enum_segment) = match remaining_index {
+            None if prefix_info.enum_variant => {
+                (segments.strip_last_two(), segments.len() - 1, Some(segments.len() - 2))
+            }
+            None => (segments.strip_last(), segments.len() - 1, None),
+            Some(i) => (segments.take(i - 1), i - 1, None),
         };
 
         for (i, mod_segment) in module_segments.iter().enumerate() {
@@ -792,9 +791,23 @@ impl<'a> TyLoweringContext<'a> {
             }
         }
 
+        if let Some(enum_segment) = enum_segment {
+            if segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some())
+                && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some())
+            {
+                on_diagnostic(
+                    self,
+                    PathLoweringDiagnostic::GenericArgsProhibited {
+                        segment: (enum_segment + 1) as u32,
+                        reason: GenericArgsProhibitedReason::EnumVariant,
+                    },
+                );
+            }
+        }
+
         self.handle_type_ns_resolution(
             &resolution,
-            resolved_segment,
+            segments.get(resolved_segment_idx).expect("should have resolved segment"),
             resolved_segment_idx,
             on_diagnostic,
         );
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index 62b071b2f32..182032f0481 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -746,16 +746,9 @@ fn lookup_impl_assoc_item_for_trait_ref(
     let table = InferenceTable::new(db, env);
 
     let (impl_data, impl_subst) = find_matching_impl(impls, table, trait_ref)?;
-    let item = impl_data.items.iter().find_map(|&it| match it {
-        AssocItemId::FunctionId(f) => {
-            (db.function_data(f).name == *name).then_some(AssocItemId::FunctionId(f))
-        }
-        AssocItemId::ConstId(c) => db
-            .const_data(c)
-            .name
-            .as_ref()
-            .map(|n| n == name)
-            .and_then(|result| if result { Some(AssocItemId::ConstId(c)) } else { None }),
+    let item = impl_data.items.iter().find_map(|(n, it)| match *it {
+        AssocItemId::FunctionId(f) => (n == name).then_some(AssocItemId::FunctionId(f)),
+        AssocItemId::ConstId(c) => (n == name).then_some(AssocItemId::ConstId(c)),
         AssocItemId::TypeAliasId(_) => None,
     })?;
     Some((item, impl_subst))
@@ -850,7 +843,7 @@ fn is_inherent_impl_coherent(
         };
         rustc_has_incoherent_inherent_impls
             && !impl_data.items.is_empty()
-            && impl_data.items.iter().copied().all(|assoc| match assoc {
+            && impl_data.items.iter().all(|&(_, assoc)| match assoc {
                 AssocItemId::FunctionId(it) => db.function_data(it).rustc_allow_incoherent_impl,
                 AssocItemId::ConstId(it) => db.const_data(it).rustc_allow_incoherent_impl,
                 AssocItemId::TypeAliasId(it) => db.type_alias_data(it).rustc_allow_incoherent_impl,
@@ -1399,7 +1392,7 @@ fn iterate_inherent_methods(
         callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
     ) -> ControlFlow<()> {
         for &impl_id in impls.for_self_ty(self_ty) {
-            for &item in table.db.impl_data(impl_id).items.iter() {
+            for &(ref item_name, item) in table.db.impl_data(impl_id).items.iter() {
                 let visible = match is_valid_impl_method_candidate(
                     table,
                     self_ty,
@@ -1408,6 +1401,7 @@ fn iterate_inherent_methods(
                     name,
                     impl_id,
                     item,
+                    item_name,
                 ) {
                     IsValidCandidate::Yes => true,
                     IsValidCandidate::NotVisible => false,
@@ -1467,6 +1461,7 @@ fn is_valid_impl_method_candidate(
     name: Option<&Name>,
     impl_id: ImplId,
     item: AssocItemId,
+    item_name: &Name,
 ) -> IsValidCandidate {
     match item {
         AssocItemId::FunctionId(f) => is_valid_impl_fn_candidate(
@@ -1477,11 +1472,12 @@ fn is_valid_impl_method_candidate(
             receiver_ty,
             self_ty,
             visible_from_module,
+            item_name,
         ),
         AssocItemId::ConstId(c) => {
             let db = table.db;
             check_that!(receiver_ty.is_none());
-            check_that!(name.is_none_or(|n| db.const_data(c).name.as_ref() == Some(n)));
+            check_that!(name.is_none_or(|n| n == item_name));
 
             if let Some(from_module) = visible_from_module {
                 if !db.const_visibility(c).is_visible_from(db.upcast(), from_module) {
@@ -1565,11 +1561,13 @@ fn is_valid_impl_fn_candidate(
     receiver_ty: Option<&Ty>,
     self_ty: &Ty,
     visible_from_module: Option<ModuleId>,
+    item_name: &Name,
 ) -> IsValidCandidate {
+    check_that!(name.is_none_or(|n| n == item_name));
+
     let db = table.db;
     let data = db.function_data(fn_id);
 
-    check_that!(name.is_none_or(|n| n == &data.name));
     if let Some(from_module) = visible_from_module {
         if !db.function_visibility(fn_id).is_visible_from(db.upcast(), from_module) {
             cov_mark::hit!(autoderef_candidate_not_visible);
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 ce43e90df7d..f1e86daea23 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
@@ -37,11 +37,15 @@ fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String),
     Ok((output.stdout().into_owned(), output.stderr().into_owned()))
 }
 
-fn check_pass(ra_fixture: &str) {
+fn check_pass(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
     check_pass_and_stdio(ra_fixture, "", "");
 }
 
-fn check_pass_and_stdio(ra_fixture: &str, expected_stdout: &str, expected_stderr: &str) {
+fn check_pass_and_stdio(
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    expected_stdout: &str,
+    expected_stderr: &str,
+) {
     let (db, file_ids) = TestDB::with_many_files(ra_fixture);
     let file_id = *file_ids.last().unwrap();
     let x = eval_main(&db, file_id);
@@ -73,7 +77,7 @@ fn check_pass_and_stdio(ra_fixture: &str, expected_stdout: &str, expected_stderr
     }
 }
 
-fn check_panic(ra_fixture: &str, expected_panic: &str) {
+fn check_panic(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected_panic: &str) {
     let (db, file_ids) = TestDB::with_many_files(ra_fixture);
     let file_id = *file_ids.last().unwrap();
     let e = eval_main(&db, file_id).unwrap_err();
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 b7607b5f639..00da9b25176 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
@@ -69,27 +69,32 @@ fn setup_tracing() -> Option<tracing::subscriber::DefaultGuard> {
 }
 
 #[track_caller]
-fn check_types(ra_fixture: &str) {
+fn check_types(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
     check_impl(ra_fixture, false, true, false)
 }
 
 #[track_caller]
-fn check_types_source_code(ra_fixture: &str) {
+fn check_types_source_code(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
     check_impl(ra_fixture, false, true, true)
 }
 
 #[track_caller]
-fn check_no_mismatches(ra_fixture: &str) {
+fn check_no_mismatches(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
     check_impl(ra_fixture, true, false, false)
 }
 
 #[track_caller]
-fn check(ra_fixture: &str) {
+fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
     check_impl(ra_fixture, false, false, false)
 }
 
 #[track_caller]
-fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_source: bool) {
+fn check_impl(
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    allow_none: bool,
+    only_types: bool,
+    display_source: bool,
+) {
     let _tracing = setup_tracing();
     let (db, files) = TestDB::with_many_files(ra_fixture);
 
@@ -282,7 +287,7 @@ fn pat_node(
     })
 }
 
-fn infer(ra_fixture: &str) -> String {
+fn infer(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String {
     infer_with_mismatches(ra_fixture, false)
 }
 
@@ -430,7 +435,7 @@ pub(crate) fn visit_module(
     visit_scope(db, crate_def_map, &crate_def_map[module_id].scope, cb);
     for impl_id in crate_def_map[module_id].scope.impls() {
         let impl_data = db.impl_data(impl_id);
-        for &item in impl_data.items.iter() {
+        for &(_, item) in impl_data.items.iter() {
             match item {
                 AssocItemId::FunctionId(it) => {
                     let body = db.body(it.into());
@@ -520,13 +525,13 @@ fn ellipsize(mut text: String, max_len: usize) -> String {
     text
 }
 
-fn check_infer(ra_fixture: &str, expect: Expect) {
+fn check_infer(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let mut actual = infer(ra_fixture);
     actual.push('\n');
     expect.assert_eq(&actual);
 }
 
-fn check_infer_with_mismatches(ra_fixture: &str, expect: Expect) {
+fn check_infer_with_mismatches(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let mut actual = infer_with_mismatches(ra_fixture, true);
     actual.push('\n');
     expect.assert_eq(&actual);
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 7de92d6b160..34d299edd1b 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
@@ -14,7 +14,7 @@ use crate::test_db::TestDB;
 
 use super::visit_module;
 
-fn check_closure_captures(ra_fixture: &str, expect: Expect) {
+fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let (db, file_id) = TestDB::with_single_file(ra_fixture);
     let module = db.module_for_file(file_id);
     let def_map = module.def_map(&db);
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 5f0f341f393..15636604570 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
@@ -3802,3 +3802,15 @@ fn foo() {
         "#,
     );
 }
+
+#[test]
+fn tool_attr_skip() {
+    check_no_mismatches(
+        r#"
+#[rust_analyzer::skip]
+async fn foo(a: (), b: i32) -> u32 {
+    0 + 1 + b()
+}
+        "#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
index 30711b16dfb..afd163fbd96 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
@@ -968,7 +968,7 @@ struct FixedPoint<T, U, V>(&'static FixedPoint<(), T, U>, V);
     }
 
     #[track_caller]
-    fn check(ra_fixture: &str, expected: Expect) {
+    fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected: Expect) {
         // use tracing_subscriber::{layer::SubscriberExt, Layer};
         // let my_layer = tracing_subscriber::fmt::layer();
         // let _g = tracing::subscriber::set_default(tracing_subscriber::registry().with(
diff --git a/src/tools/rust-analyzer/crates/hir/Cargo.toml b/src/tools/rust-analyzer/crates/hir/Cargo.toml
index 6aadc5c4f7e..c68ff706e48 100644
--- a/src/tools/rust-analyzer/crates/hir/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir/Cargo.toml
@@ -20,6 +20,7 @@ itertools.workspace = true
 smallvec.workspace = true
 tracing.workspace = true
 triomphe.workspace = true
+indexmap.workspace = true
 
 # local deps
 base-db.workspace = true
diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
index a23fdf1b393..4351a34e822 100644
--- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
@@ -12,7 +12,6 @@ use hir_def::{
 };
 use hir_expand::{mod_path::PathKind, name::Name};
 use hir_ty::{db::HirDatabase, method_resolution};
-use span::SyntaxContextId;
 
 use crate::{
     Adt, AsAssocItem, AssocItem, BuiltinType, Const, ConstParam, DocLinkDef, Enum, ExternCrateDecl,
@@ -90,6 +89,16 @@ impl HasAttrs for AssocItem {
     }
 }
 
+impl HasAttrs for crate::Crate {
+    fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner {
+        let def = AttrDefId::ModuleId(self.root_module().id);
+        AttrsWithOwner::new(db.upcast(), def)
+    }
+    fn attr_id(self) -> AttrDefId {
+        AttrDefId::ModuleId(self.root_module().id)
+    }
+}
+
 /// Resolves the item `link` points to in the scope of `def`.
 pub fn resolve_doc_path_on(
     db: &dyn HirDatabase,
@@ -328,9 +337,7 @@ fn doc_modpath_from_str(link: &str) -> Option<ModPath> {
         };
         let parts = first_segment.into_iter().chain(parts).map(|segment| match segment.parse() {
             Ok(idx) => Name::new_tuple_field(idx),
-            Err(_) => {
-                Name::new(segment.split_once('<').map_or(segment, |it| it.0), SyntaxContextId::ROOT)
-            }
+            Err(_) => Name::new_root(segment.split_once('<').map_or(segment, |it| it.0)),
         });
         Some(ModPath::from_segments(kind, parts))
     };
diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs
index e09ded32fbd..b29c91694d3 100644
--- a/src/tools/rust-analyzer/crates/hir/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/display.rs
@@ -23,10 +23,10 @@ use hir_ty::{
 use itertools::Itertools;
 
 use crate::{
-    Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Enum, ExternCrateDecl,
-    Field, Function, GenericParam, HasCrate, HasVisibility, Impl, LifetimeParam, Macro, Module,
-    SelfParam, Static, Struct, Trait, TraitAlias, TraitRef, TupleField, TyBuilder, Type, TypeAlias,
-    TypeOrConstParam, TypeParam, Union, Variant,
+    Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Crate, Enum,
+    ExternCrateDecl, Field, Function, GenericParam, HasCrate, HasVisibility, Impl, LifetimeParam,
+    Macro, Module, SelfParam, Static, Struct, Trait, TraitAlias, TraitRef, TupleField, TyBuilder,
+    Type, TypeAlias, TypeOrConstParam, TypeParam, Union, Variant,
 };
 
 impl HirDisplay for Function {
@@ -846,14 +846,27 @@ impl HirDisplay for TypeAlias {
 
 impl HirDisplay for Module {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        // FIXME: Module doesn't have visibility saved in data.
+        match self.parent(f.db) {
+            Some(m) => write_visibility(m.id, self.visibility(f.db), f)?,
+            None => {
+                return match self.krate(f.db).display_name(f.db) {
+                    Some(name) => write!(f, "extern crate {name}"),
+                    None => f.write_str("extern crate {unknown}"),
+                }
+            }
+        }
         match self.name(f.db) {
             Some(name) => write!(f, "mod {}", name.display(f.db.upcast(), f.edition())),
-            None if self.is_crate_root() => match self.krate(f.db).display_name(f.db) {
-                Some(name) => write!(f, "extern crate {name}"),
-                None => f.write_str("extern crate {unknown}"),
-            },
-            None => f.write_str("mod {unnamed}"),
+            None => f.write_str("mod {unknown}"),
+        }
+    }
+}
+
+impl HirDisplay for Crate {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+        match self.display_name(f.db) {
+            Some(name) => write!(f, "extern crate {name}"),
+            None => f.write_str("extern crate {unknown}"),
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 00b4db54374..db3121d3cd3 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -54,11 +54,11 @@ use hir_def::{
     per_ns::PerNs,
     resolver::{HasResolver, Resolver},
     type_ref::TypesSourceMap,
-    AssocItemId, AssocItemLoc, AttrDefId, CallableDefId, ConstId, ConstParamId, CrateRootModuleId,
-    DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, GenericParamId,
-    HasModule, ImplId, InTypeConstId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup,
-    MacroExpander, ModuleId, StaticId, StructId, SyntheticSyntax, TraitAliasId, TraitId, TupleId,
-    TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId,
+    AdtId, AssocItemId, AssocItemLoc, AttrDefId, CallableDefId, ConstId, ConstParamId,
+    CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FunctionId,
+    GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstId, ItemContainerId,
+    LifetimeParamId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId,
+    SyntheticSyntax, TraitAliasId, TupleId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId,
 };
 use hir_expand::{
     attrs::collect_attrs, proc_macro::ProcMacroKind, AstId, MacroCallKind, RenderedExpandError,
@@ -83,7 +83,7 @@ use itertools::Itertools;
 use nameres::diagnostics::DefDiagnosticKind;
 use rustc_hash::FxHashSet;
 use smallvec::SmallVec;
-use span::{Edition, EditionedFileId, FileId, MacroCallId, SyntaxContextId};
+use span::{Edition, EditionedFileId, FileId, MacroCallId};
 use stdx::{format_to, impl_from, never};
 use syntax::{
     ast::{self, HasAttrs as _, HasGenericParams, HasName},
@@ -127,7 +127,7 @@ pub use {
         ImportPathConfig,
         // FIXME: This is here since some queries take it as input that are used
         // outside of hir.
-        {AdtId, MacroId, ModuleDefId},
+        {ModuleDefId, TraitId},
     },
     hir_expand::{
         attrs::{Attr, AttrId},
@@ -775,29 +775,16 @@ impl Module {
                     AssocItemId::ConstId(id) => !db.const_data(id).has_body,
                     AssocItemId::TypeAliasId(it) => db.type_alias_data(it).type_ref.is_none(),
                 });
-                impl_assoc_items_scratch.extend(db.impl_data(impl_def.id).items.iter().filter_map(
-                    |&item| {
-                        Some((
-                            item,
-                            match item {
-                                AssocItemId::FunctionId(it) => db.function_data(it).name.clone(),
-                                AssocItemId::ConstId(it) => {
-                                    db.const_data(it).name.as_ref()?.clone()
-                                }
-                                AssocItemId::TypeAliasId(it) => db.type_alias_data(it).name.clone(),
-                            },
-                        ))
-                    },
-                ));
+                impl_assoc_items_scratch.extend(db.impl_data(impl_def.id).items.iter().cloned());
 
                 let redundant = impl_assoc_items_scratch
                     .iter()
-                    .filter(|(id, name)| {
+                    .filter(|(name, id)| {
                         !items.iter().any(|(impl_name, impl_item)| {
                             discriminant(impl_item) == discriminant(id) && impl_name == name
                         })
                     })
-                    .map(|(item, name)| (name.clone(), AssocItem::from(*item)));
+                    .map(|(name, item)| (name.clone(), AssocItem::from(*item)));
                 for (name, assoc_item) in redundant {
                     acc.push(
                         TraitImplRedundantAssocItems {
@@ -812,7 +799,7 @@ impl Module {
 
                 let missing: Vec<_> = required_items
                     .filter(|(name, id)| {
-                        !impl_assoc_items_scratch.iter().any(|(impl_item, impl_name)| {
+                        !impl_assoc_items_scratch.iter().any(|(impl_name, impl_item)| {
                             discriminant(impl_item) == discriminant(id) && impl_name == name
                         })
                     })
@@ -844,7 +831,7 @@ impl Module {
                 source_map,
             );
 
-            for &item in db.impl_data(impl_def.id).items.iter() {
+            for &(_, item) in db.impl_data(impl_def.id).items.iter() {
                 AssocItem::from(item).diagnostics(db, acc, style_lints);
             }
         }
@@ -3000,6 +2987,10 @@ impl Macro {
         matches!(self.id, MacroId::MacroRulesId(id) if db.macro_rules_data(id).macro_export)
     }
 
+    pub fn is_proc_macro(self) -> bool {
+        matches!(self.id, MacroId::ProcMacroId(_))
+    }
+
     pub fn kind(&self, db: &dyn HirDatabase) -> MacroKind {
         match self.id {
             MacroId::Macro2Id(it) => match it.lookup(db.upcast()).expander {
@@ -3046,14 +3037,23 @@ impl Macro {
             MacroId::Macro2Id(it) => {
                 matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltInEager(eager) if eager.is_env_or_option_env())
             }
-            MacroId::MacroRulesId(_) | MacroId::ProcMacroId(_) => false,
+            MacroId::MacroRulesId(it) => {
+                matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltInEager(eager) if eager.is_env_or_option_env())
+            }
+            MacroId::ProcMacroId(_) => false,
         }
     }
 
     pub fn is_asm_or_global_asm(&self, db: &dyn HirDatabase) -> bool {
-        matches!(self.id, MacroId::Macro2Id(it) if {
-            matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltIn(m) if m.is_asm())
-        })
+        match self.id {
+            MacroId::Macro2Id(it) => {
+                matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltIn(m) if m.is_asm())
+            }
+            MacroId::MacroRulesId(it) => {
+                matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltIn(m) if m.is_asm())
+            }
+            MacroId::ProcMacroId(_) => false,
+        }
     }
 
     pub fn is_attr(&self, db: &dyn HirDatabase) -> bool {
@@ -3902,6 +3902,10 @@ impl ToolModule {
             db.crate_def_map(self.krate).registered_tools()[self.idx as usize].clone(),
         )
     }
+
+    pub fn krate(&self) -> Crate {
+        Crate { id: self.krate }
+    }
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
@@ -4290,7 +4294,7 @@ impl Impl {
     }
 
     pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
-        db.impl_data(self.id).items.iter().map(|&it| it.into()).collect()
+        db.impl_data(self.id).items.iter().map(|&(_, it)| it.into()).collect()
     }
 
     pub fn is_negative(self, db: &dyn HirDatabase) -> bool {
@@ -4731,6 +4735,14 @@ impl Type {
         Some((self.derived(ty.clone()), m))
     }
 
+    pub fn add_reference(&self, mutability: Mutability) -> Type {
+        let ty_mutability = match mutability {
+            Mutability::Shared => hir_ty::Mutability::Not,
+            Mutability::Mut => hir_ty::Mutability::Mut,
+        };
+        self.derived(TyKind::Ref(ty_mutability, error_lifetime(), self.ty.clone()).intern(Interner))
+    }
+
     pub fn is_slice(&self) -> bool {
         matches!(self.ty.kind(Interner), TyKind::Slice(..))
     }
@@ -4786,9 +4798,9 @@ impl Type {
     }
 
     /// Checks that particular type `ty` implements `std::future::IntoFuture` or
-    /// `std::future::Future`.
+    /// `std::future::Future` and returns the `Output` associated type.
     /// This function is used in `.await` syntax completion.
-    pub fn impls_into_future(&self, db: &dyn HirDatabase) -> bool {
+    pub fn into_future_output(&self, db: &dyn HirDatabase) -> Option<Type> {
         let trait_ = db
             .lang_item(self.env.krate, LangItem::IntoFutureIntoFuture)
             .and_then(|it| {
@@ -4800,16 +4812,18 @@ impl Type {
             .or_else(|| {
                 let future_trait = db.lang_item(self.env.krate, LangItem::Future)?;
                 future_trait.as_trait()
-            });
-
-        let trait_ = match trait_ {
-            Some(it) => it,
-            None => return false,
-        };
+            })?;
 
         let canonical_ty =
             Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) };
-        method_resolution::implements_trait(&canonical_ty, db, &self.env, trait_)
+        if !method_resolution::implements_trait_unique(&canonical_ty, db, &self.env, trait_) {
+            return None;
+        }
+
+        let output_assoc_type = db
+            .trait_data(trait_)
+            .associated_type_by_name(&Name::new_symbol_root(sym::Output.clone()))?;
+        self.normalize_trait_assoc_type(db, &[], output_assoc_type.into())
     }
 
     /// This does **not** resolve `IntoFuture`, only `Future`.
@@ -4824,10 +4838,31 @@ impl Type {
         let iterator_trait = db.lang_item(self.env.krate, LangItem::Iterator)?.as_trait()?;
         let iterator_item = db
             .trait_data(iterator_trait)
-            .associated_type_by_name(&Name::new_symbol(sym::Item.clone(), SyntaxContextId::ROOT))?;
+            .associated_type_by_name(&Name::new_symbol_root(sym::Item.clone()))?;
         self.normalize_trait_assoc_type(db, &[], iterator_item.into())
     }
 
+    /// Resolves the projection `<Self as IntoIterator>::IntoIter` and returns the resulting type
+    pub fn into_iterator_iter(self, db: &dyn HirDatabase) -> Option<Type> {
+        let trait_ = db.lang_item(self.env.krate, LangItem::IntoIterIntoIter).and_then(|it| {
+            let into_iter_fn = it.as_function()?;
+            let assoc_item = as_assoc_item(db, AssocItem::Function, into_iter_fn)?;
+            let into_iter_trait = assoc_item.container_or_implemented_trait(db)?;
+            Some(into_iter_trait.id)
+        })?;
+
+        let canonical_ty =
+            Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) };
+        if !method_resolution::implements_trait_unique(&canonical_ty, db, &self.env, trait_) {
+            return None;
+        }
+
+        let into_iter_assoc_type = db
+            .trait_data(trait_)
+            .associated_type_by_name(&Name::new_symbol_root(sym::IntoIter.clone()))?;
+        self.normalize_trait_assoc_type(db, &[], into_iter_assoc_type.into())
+    }
+
     /// Checks that particular type `ty` implements `std::ops::FnOnce`.
     ///
     /// This function can be used to check if a particular type is callable, since FnOnce is a
@@ -5117,7 +5152,7 @@ impl Type {
             let impls = db.inherent_impls_in_crate(krate);
 
             for impl_def in impls.for_self_ty(&self.ty) {
-                for &item in db.impl_data(*impl_def).items.iter() {
+                for &(_, item) in db.impl_data(*impl_def).items.iter() {
                     if callback(item) {
                         return;
                     }
@@ -5535,6 +5570,7 @@ impl Type {
                     walk_substs(db, type_, &opaque_ty.substitution, cb);
                 }
                 TyKind::Placeholder(_) => {
+                    cb(type_.derived(ty.clone()));
                     if let Some(bounds) = ty.impl_trait_bounds(db) {
                         walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
                     }
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 34d169cd761..523bc6f10aa 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -39,8 +39,8 @@ use stdx::TupleExt;
 use syntax::{
     algo::skip_trivia_token,
     ast::{self, HasAttrs as _, HasGenericParams},
-    AstNode, AstToken, Direction, SmolStr, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken,
-    TextRange, TextSize,
+    AstNode, AstToken, Direction, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange,
+    TextSize,
 };
 use triomphe::Arc;
 
@@ -136,8 +136,6 @@ pub struct Semantics<'db, DB> {
 pub struct SemanticsImpl<'db> {
     pub db: &'db dyn HirDatabase,
     s2d_cache: RefCell<SourceToDefCache>,
-    /// Rootnode to HirFileId cache
-    root_to_file_cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>,
     /// MacroCall to its expansion's MacroFileId cache
     macro_call_cache: RefCell<FxHashMap<InFile<ast::MacroCall>, MacroFileId>>,
 }
@@ -304,12 +302,7 @@ impl<DB: HirDatabase> Semantics<'_, DB> {
 
 impl<'db> SemanticsImpl<'db> {
     fn new(db: &'db dyn HirDatabase) -> Self {
-        SemanticsImpl {
-            db,
-            s2d_cache: Default::default(),
-            root_to_file_cache: Default::default(),
-            macro_call_cache: Default::default(),
-        }
+        SemanticsImpl { db, s2d_cache: Default::default(), macro_call_cache: Default::default() }
     }
 
     pub fn parse(&self, file_id: EditionedFileId) -> ast::SourceFile {
@@ -483,7 +476,7 @@ impl<'db> SemanticsImpl<'db> {
             Some(
                 calls
                     .into_iter()
-                    .map(|call| macro_call_to_macro_id(self, ctx, call?).map(|id| Macro { id }))
+                    .map(|call| macro_call_to_macro_id(ctx, call?).map(|id| Macro { id }))
                     .collect(),
             )
         })
@@ -962,7 +955,7 @@ impl<'db> SemanticsImpl<'db> {
             let InMacroFile { file_id, value: mapped_tokens } = self.with_ctx(|ctx| {
                 Some(
                     ctx.cache
-                        .get_or_insert_expansion(self, macro_file)
+                        .get_or_insert_expansion(ctx.db, macro_file)
                         .map_range_down(span)?
                         .map(SmallVec::<[_; 2]>::from_iter),
                 )
@@ -986,7 +979,10 @@ impl<'db> SemanticsImpl<'db> {
                 process_expansion_for_token(&mut stack, include)?;
             }
             None => {
-                stack.push((file_id.into(), smallvec![(token, SyntaxContextId::ROOT)]));
+                stack.push((
+                    file_id.into(),
+                    smallvec![(token, SyntaxContextId::root(file_id.edition()))],
+                ));
             }
         }
 
@@ -1284,7 +1280,7 @@ impl<'db> SemanticsImpl<'db> {
                     let macro_file = file_id.macro_file()?;
 
                     self.with_ctx(|ctx| {
-                        let expansion_info = ctx.cache.get_or_insert_expansion(self, macro_file);
+                        let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file);
                         expansion_info.arg().map(|node| node?.parent()).transpose()
                     })
                 }
@@ -1315,8 +1311,8 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     pub fn resolve_label(&self, label: &ast::Lifetime) -> Option<Label> {
-        let (parent, label_id) = self
-            .with_ctx(|ctx| ctx.label_ref_to_def(self.wrap_node_infile(label.clone()).as_ref()))?;
+        let src = self.wrap_node_infile(label.clone());
+        let (parent, label_id) = self.with_ctx(|ctx| ctx.label_ref_to_def(src.as_ref()))?;
         Some(Label { parent, label_id })
     }
 
@@ -1443,6 +1439,10 @@ impl<'db> SemanticsImpl<'db> {
         self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call)
     }
 
+    pub fn resolve_known_blanket_dual_impls(&self, call: &ast::MethodCallExpr) -> Option<Function> {
+        self.analyze(call.syntax())?.resolve_known_blanket_dual_impls(self.db, call)
+    }
+
     fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<StructId> {
         self.analyze(range_pat.syntax())?.resolve_range_pat(self.db, range_pat)
     }
@@ -1516,7 +1516,7 @@ impl<'db> SemanticsImpl<'db> {
         let macro_call = self.find_file(macro_call.syntax()).with_value(macro_call);
         self.with_ctx(|ctx| {
             ctx.macro_call_to_macro_call(macro_call)
-                .and_then(|call| macro_call_to_macro_id(self, ctx, call))
+                .and_then(|call| macro_call_to_macro_id(ctx, call))
                 .map(Into::into)
         })
         .or_else(|| {
@@ -1558,7 +1558,7 @@ impl<'db> SemanticsImpl<'db> {
         let item_in_file = self.wrap_node_infile(item.clone());
         let id = self.with_ctx(|ctx| {
             let macro_call_id = ctx.item_to_macro_call(item_in_file.as_ref())?;
-            macro_call_to_macro_id(self, ctx, macro_call_id)
+            macro_call_to_macro_id(ctx, macro_call_id)
         })?;
         Some(Macro { id })
     }
@@ -1591,14 +1591,11 @@ impl<'db> SemanticsImpl<'db> {
     pub fn resolve_mod_path_relative(
         &self,
         to: Module,
-        segments: impl IntoIterator<Item = SmolStr>,
+        segments: impl IntoIterator<Item = Name>,
     ) -> Option<impl Iterator<Item = ItemInNs>> {
         let items = to.id.resolver(self.db.upcast()).resolve_module_path_in_items(
             self.db.upcast(),
-            &ModPath::from_segments(
-                hir_def::path::PathKind::Plain,
-                segments.into_iter().map(|it| Name::new(&it, SyntaxContextId::ROOT)),
-            ),
+            &ModPath::from_segments(hir_def::path::PathKind::Plain, segments),
         );
         Some(items.iter_items().map(|(item, _)| item.into()))
     }
@@ -1722,10 +1719,11 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) {
-        assert!(root_node.parent().is_none());
-        let mut cache = self.root_to_file_cache.borrow_mut();
-        let prev = cache.insert(root_node, file_id);
-        assert!(prev.is_none() || prev == Some(file_id));
+        SourceToDefCache::cache(
+            &mut self.s2d_cache.borrow_mut().root_to_file_cache,
+            root_node,
+            file_id,
+        );
     }
 
     pub fn assert_contains_node(&self, node: &SyntaxNode) {
@@ -1733,8 +1731,8 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     fn lookup(&self, root_node: &SyntaxNode) -> Option<HirFileId> {
-        let cache = self.root_to_file_cache.borrow();
-        cache.get(root_node).copied()
+        let cache = self.s2d_cache.borrow();
+        cache.root_to_file_cache.get(root_node).copied()
     }
 
     fn wrap_node_infile<N: AstNode>(&self, node: N) -> InFile<N> {
@@ -1753,13 +1751,14 @@ impl<'db> SemanticsImpl<'db> {
         let file_id = self.lookup(&root_node).unwrap_or_else(|| {
             panic!(
                 "\n\nFailed to lookup {:?} in this Semantics.\n\
-                 Make sure to use only query nodes, derived from this instance of Semantics.\n\
+                 Make sure to only query nodes derived from this instance of Semantics.\n\
                  root node:   {:?}\n\
                  known nodes: {}\n\n",
                 node,
                 root_node,
-                self.root_to_file_cache
+                self.s2d_cache
                     .borrow()
+                    .root_to_file_cache
                     .keys()
                     .map(|it| format!("{it:?}"))
                     .collect::<Vec<_>>()
@@ -1906,7 +1905,6 @@ impl<'db> SemanticsImpl<'db> {
 }
 
 fn macro_call_to_macro_id(
-    sema: &SemanticsImpl<'_>,
     ctx: &mut SourceToDefCtx<'_, '_>,
     macro_call_id: MacroCallId,
 ) -> Option<MacroId> {
@@ -1922,7 +1920,7 @@ fn macro_call_to_macro_id(
                     it.to_ptr(db).to_node(&db.parse(file_id).syntax_node())
                 }
                 HirFileIdRepr::MacroFile(macro_file) => {
-                    let expansion_info = ctx.cache.get_or_insert_expansion(sema, macro_file);
+                    let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file);
                     it.to_ptr(db).to_node(&expansion_info.expanded().value)
                 }
             };
@@ -1934,7 +1932,7 @@ fn macro_call_to_macro_id(
                     it.to_ptr(db).to_node(&db.parse(file_id).syntax_node())
                 }
                 HirFileIdRepr::MacroFile(macro_file) => {
-                    let expansion_info = ctx.cache.get_or_insert_expansion(sema, macro_file);
+                    let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file);
                     it.to_ptr(db).to_node(&expansion_info.expanded().value)
                 }
             };
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs
index ec65ea9a9a8..d5dfb985718 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs
@@ -56,7 +56,7 @@ impl ChildBySource for ImplId {
                 res[keys::ATTR_MACRO_CALL].insert(ast_id.to_ptr(db.upcast()), call_id);
             },
         );
-        data.items.iter().for_each(|&item| {
+        data.items.iter().for_each(|&(_, item)| {
             add_assoc_item(db, res, file_id, item);
         });
     }
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
index b5cc440fc22..3c9e7065c41 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
@@ -110,10 +110,7 @@ use syntax::{
     AstNode, AstPtr, SyntaxNode,
 };
 
-use crate::{
-    db::HirDatabase, semantics::child_by_source::ChildBySource, InFile, InlineAsmOperand,
-    SemanticsImpl,
-};
+use crate::{db::HirDatabase, semantics::child_by_source::ChildBySource, InFile, InlineAsmOperand};
 
 #[derive(Default)]
 pub(super) struct SourceToDefCache {
@@ -121,9 +118,21 @@ pub(super) struct SourceToDefCache {
     expansion_info_cache: FxHashMap<MacroFileId, ExpansionInfo>,
     pub(super) file_to_def_cache: FxHashMap<FileId, SmallVec<[ModuleId; 1]>>,
     pub(super) included_file_cache: FxHashMap<EditionedFileId, Option<MacroFileId>>,
+    /// Rootnode to HirFileId cache
+    pub(super) root_to_file_cache: FxHashMap<SyntaxNode, HirFileId>,
 }
 
 impl SourceToDefCache {
+    pub(super) fn cache(
+        root_to_file_cache: &mut FxHashMap<SyntaxNode, HirFileId>,
+        root_node: SyntaxNode,
+        file_id: HirFileId,
+    ) {
+        assert!(root_node.parent().is_none());
+        let prev = root_to_file_cache.insert(root_node, file_id);
+        assert!(prev.is_none() || prev == Some(file_id));
+    }
+
     pub(super) fn get_or_insert_include_for(
         &mut self,
         db: &dyn HirDatabase,
@@ -143,14 +152,14 @@ impl SourceToDefCache {
 
     pub(super) fn get_or_insert_expansion(
         &mut self,
-        sema: &SemanticsImpl<'_>,
+        db: &dyn HirDatabase,
         macro_file: MacroFileId,
     ) -> &ExpansionInfo {
         self.expansion_info_cache.entry(macro_file).or_insert_with(|| {
-            let exp_info = macro_file.expansion_info(sema.db.upcast());
+            let exp_info = macro_file.expansion_info(db.upcast());
 
             let InMacroFile { file_id, value } = exp_info.expanded();
-            sema.cache(value, file_id.into());
+            Self::cache(&mut self.root_to_file_cache, value, file_id.into());
 
             exp_info
         })
@@ -520,18 +529,11 @@ impl SourceToDefCtx<'_, '_> {
         node: InFile<&SyntaxNode>,
         mut cb: impl FnMut(&mut Self, InFile<SyntaxNode>) -> Option<T>,
     ) -> Option<T> {
-        use hir_expand::MacroFileIdExt;
         let parent = |this: &mut Self, node: InFile<&SyntaxNode>| match node.value.parent() {
             Some(parent) => Some(node.with_value(parent)),
             None => {
                 let macro_file = node.file_id.macro_file()?;
-
-                let expansion_info = this
-                    .cache
-                    .expansion_info_cache
-                    .entry(macro_file)
-                    .or_insert_with(|| macro_file.expansion_info(this.db.upcast()));
-
+                let expansion_info = this.cache.get_or_insert_expansion(this.db, macro_file);
                 expansion_info.arg().map(|node| node?.parent()).transpose()
             }
         };
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 b699ccde412..6b78d7a3631 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -322,6 +322,68 @@ impl SourceAnalyzer {
         }
     }
 
+    // If the method is into(), try_into(), parse(), resolve it to from, try_from, from_str.
+    pub(crate) fn resolve_known_blanket_dual_impls(
+        &self,
+        db: &dyn HirDatabase,
+        call: &ast::MethodCallExpr,
+    ) -> Option<Function> {
+        // e.g. if the method call is let b = a.into(),
+        // - receiver_type is A (type of a)
+        // - return_type is B (type of b)
+        // We will find the definition of B::from(a: A).
+        let callable = self.resolve_method_call_as_callable(db, call)?;
+        let (_, receiver_type) = callable.receiver_param(db)?;
+        let return_type = callable.return_type();
+        let (search_method, substs) = match call.name_ref()?.text().as_str() {
+            "into" => {
+                let trait_ =
+                    self.resolver.resolve_known_trait(db.upcast(), &path![core::convert::From])?;
+                (
+                    self.trait_fn(db, trait_, "from")?,
+                    hir_ty::TyBuilder::subst_for_def(db, trait_, None)
+                        .push(return_type.ty)
+                        .push(receiver_type.ty)
+                        .build(),
+                )
+            }
+            "try_into" => {
+                let trait_ = self
+                    .resolver
+                    .resolve_known_trait(db.upcast(), &path![core::convert::TryFrom])?;
+                (
+                    self.trait_fn(db, trait_, "try_from")?,
+                    hir_ty::TyBuilder::subst_for_def(db, trait_, None)
+                        // If the method is try_into() or parse(), return_type is Result<T, Error>.
+                        // Get T from type arguments of Result<T, Error>.
+                        .push(return_type.type_arguments().next()?.ty)
+                        .push(receiver_type.ty)
+                        .build(),
+                )
+            }
+            "parse" => {
+                let trait_ =
+                    self.resolver.resolve_known_trait(db.upcast(), &path![core::str::FromStr])?;
+                (
+                    self.trait_fn(db, trait_, "from_str")?,
+                    hir_ty::TyBuilder::subst_for_def(db, trait_, None)
+                        .push(return_type.type_arguments().next()?.ty)
+                        .build(),
+                )
+            }
+            _ => return None,
+        };
+
+        let found_method = self.resolve_impl_method_or_trait_def(db, search_method, substs);
+        // If found_method == search_method, the method in trait itself is resolved.
+        // It means the blanket dual impl is not found.
+        if found_method == search_method {
+            None
+        } else {
+            Some(found_method.into())
+        }
+    }
+
     pub(crate) fn resolve_expr_as_callable(
         &self,
         db: &dyn HirDatabase,
@@ -1247,6 +1309,18 @@ impl SourceAnalyzer {
         Some((trait_id, fn_id))
     }
 
+    fn trait_fn(
+        &self,
+        db: &dyn HirDatabase,
+        trait_id: TraitId,
+        method_name: &str,
+    ) -> Option<FunctionId> {
+        db.trait_data(trait_id).items.iter().find_map(|(item_name, item)| match item {
+            AssocItemId::FunctionId(t) if item_name.as_str() == method_name => Some(*t),
+            _ => None,
+        })
+    }
+
     fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {
         self.infer.as_ref()?.type_of_expr_or_pat(self.expr_id(db, expr)?)
     }
diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
index f8416f86bf9..a6b8ed70c36 100644
--- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
@@ -1,27 +1,34 @@
 //! File symbol extraction.
 
+use either::Either;
 use hir_def::{
     db::DefDatabase,
-    item_scope::ItemInNs,
+    item_scope::{ImportId, ImportOrExternCrate},
+    per_ns::Item,
     src::{HasChildSource, HasSource},
-    AdtId, AssocItemId, DefWithBodyId, HasModule, ImplId, Lookup, MacroId, ModuleDefId, ModuleId,
-    TraitId,
+    visibility::{Visibility, VisibilityExplicitness},
+    AdtId, AssocItemId, DefWithBodyId, ExternCrateId, HasModule, ImplId, Lookup, MacroId,
+    ModuleDefId, ModuleId, TraitId,
 };
-use hir_expand::HirFileId;
+use hir_expand::{name::Name, HirFileId};
 use hir_ty::{
     db::HirDatabase,
     display::{hir_display_with_types_map, 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};
 
+pub type FxIndexSet<T> = indexmap::IndexSet<T, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
+
 /// The actual data that is stored in the index. It should be as compact as
 /// possible.
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct FileSymbol {
-    pub name: SmolStr,
+    pub name: Symbol,
     pub def: ModuleDef,
     pub loc: DeclarationLocation,
     pub container_name: Option<SmolStr>,
@@ -37,7 +44,7 @@ pub struct DeclarationLocation {
     /// This points to the whole syntax node of the declaration.
     pub ptr: SyntaxNodePtr,
     /// This points to the [`syntax::ast::Name`] identifier of the declaration.
-    pub name_ptr: AstPtr<syntax::ast::Name>,
+    pub name_ptr: AstPtr<Either<syntax::ast::Name, syntax::ast::NameRef>>,
 }
 
 impl DeclarationLocation {
@@ -55,7 +62,7 @@ struct SymbolCollectorWork {
 
 pub struct SymbolCollector<'a> {
     db: &'a dyn HirDatabase,
-    symbols: Vec<FileSymbol>,
+    symbols: FxIndexSet<FileSymbol>,
     work: Vec<SymbolCollectorWork>,
     current_container_name: Option<SmolStr>,
     edition: Edition,
@@ -86,11 +93,11 @@ impl<'a> SymbolCollector<'a> {
         }
     }
 
-    pub fn finish(self) -> Vec<FileSymbol> {
-        self.symbols
+    pub fn finish(self) -> Box<[FileSymbol]> {
+        self.symbols.into_iter().collect()
     }
 
-    pub fn collect_module(db: &dyn HirDatabase, module: Module) -> Vec<FileSymbol> {
+    pub fn collect_module(db: &dyn HirDatabase, module: Module) -> Box<[FileSymbol]> {
         let mut symbol_collector = SymbolCollector::new(db);
         symbol_collector.collect(module);
         symbol_collector.finish()
@@ -104,96 +111,174 @@ impl<'a> SymbolCollector<'a> {
     }
 
     fn collect_from_module(&mut self, module_id: ModuleId) {
-        let def_map = module_id.def_map(self.db.upcast());
-        let scope = &def_map[module_id.local_id].scope;
-
-        for module_def_id in scope.declarations() {
-            match module_def_id {
-                ModuleDefId::ModuleId(id) => self.push_module(id),
+        let push_decl = |this: &mut Self, def, name| {
+            match def {
+                ModuleDefId::ModuleId(id) => this.push_module(id, name),
                 ModuleDefId::FunctionId(id) => {
-                    self.push_decl(id, false);
-                    self.collect_from_body(id);
+                    this.push_decl(id, name, false);
+                    this.collect_from_body(id);
                 }
-                ModuleDefId::AdtId(AdtId::StructId(id)) => self.push_decl(id, false),
-                ModuleDefId::AdtId(AdtId::EnumId(id)) => self.push_decl(id, false),
-                ModuleDefId::AdtId(AdtId::UnionId(id)) => self.push_decl(id, false),
+                ModuleDefId::AdtId(AdtId::StructId(id)) => this.push_decl(id, name, false),
+                ModuleDefId::AdtId(AdtId::EnumId(id)) => this.push_decl(id, name, false),
+                ModuleDefId::AdtId(AdtId::UnionId(id)) => this.push_decl(id, name, false),
                 ModuleDefId::ConstId(id) => {
-                    self.push_decl(id, false);
-                    self.collect_from_body(id);
+                    this.push_decl(id, name, false);
+                    this.collect_from_body(id);
                 }
                 ModuleDefId::StaticId(id) => {
-                    self.push_decl(id, false);
-                    self.collect_from_body(id);
+                    this.push_decl(id, name, false);
+                    this.collect_from_body(id);
                 }
                 ModuleDefId::TraitId(id) => {
-                    self.push_decl(id, false);
-                    self.collect_from_trait(id);
+                    this.push_decl(id, name, false);
+                    this.collect_from_trait(id);
                 }
                 ModuleDefId::TraitAliasId(id) => {
-                    self.push_decl(id, false);
+                    this.push_decl(id, name, false);
                 }
                 ModuleDefId::TypeAliasId(id) => {
-                    self.push_decl(id, false);
+                    this.push_decl(id, name, false);
                 }
                 ModuleDefId::MacroId(id) => match id {
-                    MacroId::Macro2Id(id) => self.push_decl(id, false),
-                    MacroId::MacroRulesId(id) => self.push_decl(id, false),
-                    MacroId::ProcMacroId(id) => self.push_decl(id, false),
+                    MacroId::Macro2Id(id) => this.push_decl(id, name, false),
+                    MacroId::MacroRulesId(id) => this.push_decl(id, name, false),
+                    MacroId::ProcMacroId(id) => this.push_decl(id, name, false),
                 },
                 // Don't index these.
                 ModuleDefId::BuiltinType(_) => {}
                 ModuleDefId::EnumVariantId(_) => {}
             }
-        }
+        };
 
-        for impl_id in scope.impls() {
-            self.collect_from_impl(impl_id);
-        }
+        // Nested trees are very common, so a cache here will hit a lot.
+        let import_child_source_cache = &mut FxHashMap::default();
+
+        let mut push_import = |this: &mut Self, i: ImportId, name: &Name, def: ModuleDefId| {
+            let source = import_child_source_cache
+                .entry(i.import)
+                .or_insert_with(|| i.import.child_source(this.db.upcast()));
+            let Some(use_tree_src) = source.value.get(i.idx) else { return };
+            let Some(name_ptr) = use_tree_src
+                .rename()
+                .and_then(|rename| rename.name())
+                .map(Either::Left)
+                .or_else(|| use_tree_src.path()?.segment()?.name_ref().map(Either::Right))
+                .map(|it| AstPtr::new(&it))
+            else {
+                return;
+            };
+            let dec_loc = DeclarationLocation {
+                hir_file_id: source.file_id,
+                ptr: SyntaxNodePtr::new(use_tree_src.syntax()),
+                name_ptr,
+            };
+            this.symbols.insert(FileSymbol {
+                name: name.symbol().clone(),
+                def: def.into(),
+                container_name: this.current_container_name.clone(),
+                loc: dec_loc,
+                is_alias: false,
+                is_assoc: false,
+            });
+        };
 
-        // Record renamed imports.
-        // FIXME: In case it imports multiple items under different namespaces we just pick one arbitrarily
-        // for now.
-        for id in scope.imports() {
-            let source = id.import.child_source(self.db.upcast());
-            let Some(use_tree_src) = source.value.get(id.idx) else { continue };
-            let Some(rename) = use_tree_src.rename() else { continue };
-            let Some(name) = rename.name() else { continue };
-
-            let res = scope.fully_resolve_import(self.db.upcast(), id);
-            res.iter_items().for_each(|(item, _)| {
-                let def = match item {
-                    ItemInNs::Types(def) | ItemInNs::Values(def) => def,
-                    ItemInNs::Macros(def) => ModuleDefId::from(def),
-                }
-                .into();
+        let push_extern_crate =
+            |this: &mut Self, i: ExternCrateId, name: &Name, def: ModuleDefId| {
+                let loc = i.lookup(this.db.upcast());
+                let source = loc.source(this.db.upcast());
+                let Some(name_ptr) = source
+                    .value
+                    .rename()
+                    .and_then(|rename| rename.name())
+                    .map(Either::Left)
+                    .or_else(|| source.value.name_ref().map(Either::Right))
+                    .map(|it| AstPtr::new(&it))
+                else {
+                    return;
+                };
                 let dec_loc = DeclarationLocation {
                     hir_file_id: source.file_id,
-                    ptr: SyntaxNodePtr::new(use_tree_src.syntax()),
-                    name_ptr: AstPtr::new(&name),
+                    ptr: SyntaxNodePtr::new(source.value.syntax()),
+                    name_ptr,
                 };
-
-                self.symbols.push(FileSymbol {
-                    name: name.text().into(),
-                    def,
-                    container_name: self.current_container_name.clone(),
+                this.symbols.insert(FileSymbol {
+                    name: name.symbol().clone(),
+                    def: def.into(),
+                    container_name: this.current_container_name.clone(),
                     loc: dec_loc,
                     is_alias: false,
                     is_assoc: false,
                 });
-            });
+            };
+
+        let is_explicit_import = |vis| {
+            match vis {
+                Visibility::Module(_, VisibilityExplicitness::Explicit) => true,
+                Visibility::Module(_, VisibilityExplicitness::Implicit) => {
+                    // consider imports in the crate root explicit, as these are visibly
+                    // crate-wide anyways
+                    module_id.is_crate_root()
+                }
+                Visibility::Public => true,
+            }
+        };
+
+        let def_map = module_id.def_map(self.db.upcast());
+        let scope = &def_map[module_id.local_id].scope;
+
+        for impl_id in scope.impls() {
+            self.collect_from_impl(impl_id);
+        }
+
+        for (name, Item { def, vis, import }) in scope.types() {
+            if let Some(i) = import {
+                if is_explicit_import(vis) {
+                    match i {
+                        ImportOrExternCrate::Import(i) => push_import(self, i, name, def),
+                        ImportOrExternCrate::ExternCrate(i) => {
+                            push_extern_crate(self, i, name, def)
+                        }
+                    }
+                }
+                continue;
+            }
+            // self is a declaration
+            push_decl(self, def, name)
+        }
+
+        for (name, Item { def, vis, import }) in scope.macros() {
+            if let Some(i) = import {
+                if is_explicit_import(vis) {
+                    push_import(self, i, name, def.into());
+                }
+                continue;
+            }
+            // self is a declaration
+            push_decl(self, def.into(), name)
+        }
+
+        for (name, Item { def, vis, import }) in scope.values() {
+            if let Some(i) = import {
+                if is_explicit_import(vis) {
+                    push_import(self, i, name, def);
+                }
+                continue;
+            }
+            // self is a declaration
+            push_decl(self, def, name)
         }
 
         for const_id in scope.unnamed_consts() {
             self.collect_from_body(const_id);
         }
 
-        for (_, id) in scope.legacy_macros() {
+        for (name, id) in scope.legacy_macros() {
             for &id in id {
                 if id.module(self.db.upcast()) == module_id {
                     match id {
-                        MacroId::Macro2Id(id) => self.push_decl(id, false),
-                        MacroId::MacroRulesId(id) => self.push_decl(id, false),
-                        MacroId::ProcMacroId(id) => self.push_decl(id, false),
+                        MacroId::Macro2Id(id) => self.push_decl(id, name, false),
+                        MacroId::MacroRulesId(id) => self.push_decl(id, name, false),
+                        MacroId::ProcMacroId(id) => self.push_decl(id, name, false),
                     }
                 }
             }
@@ -223,8 +308,8 @@ impl<'a> SymbolCollector<'a> {
                 .to_smolstr(),
         );
         self.with_container_name(impl_name, |s| {
-            for &assoc_item_id in impl_data.items.iter() {
-                s.push_assoc_item(assoc_item_id)
+            for &(ref name, assoc_item_id) in &impl_data.items {
+                s.push_assoc_item(assoc_item_id, name)
             }
         })
     }
@@ -232,8 +317,8 @@ impl<'a> SymbolCollector<'a> {
     fn collect_from_trait(&mut self, trait_id: TraitId) {
         let trait_data = self.db.trait_data(trait_id);
         self.with_container_name(Some(trait_data.name.as_str().into()), |s| {
-            for &(_, assoc_item_id) in &trait_data.items {
-                s.push_assoc_item(assoc_item_id);
+            for &(ref name, assoc_item_id) in &trait_data.items {
+                s.push_assoc_item(assoc_item_id, name);
             }
         });
     }
@@ -266,15 +351,15 @@ impl<'a> SymbolCollector<'a> {
         }
     }
 
-    fn push_assoc_item(&mut self, assoc_item_id: AssocItemId) {
+    fn push_assoc_item(&mut self, assoc_item_id: AssocItemId, name: &Name) {
         match assoc_item_id {
-            AssocItemId::FunctionId(id) => self.push_decl(id, true),
-            AssocItemId::ConstId(id) => self.push_decl(id, true),
-            AssocItemId::TypeAliasId(id) => self.push_decl(id, true),
+            AssocItemId::FunctionId(id) => self.push_decl(id, name, true),
+            AssocItemId::ConstId(id) => self.push_decl(id, name, true),
+            AssocItemId::TypeAliasId(id) => self.push_decl(id, name, true),
         }
     }
 
-    fn push_decl<'db, L>(&mut self, id: L, is_assoc: bool)
+    fn push_decl<'db, L>(&mut self, id: L, name: &Name, is_assoc: bool)
     where
         L: Lookup<Database<'db> = dyn DefDatabase + 'db> + Into<ModuleDefId>,
         <L as Lookup>::Data: HasSource,
@@ -287,13 +372,13 @@ impl<'a> SymbolCollector<'a> {
         let dec_loc = DeclarationLocation {
             hir_file_id: source.file_id,
             ptr: SyntaxNodePtr::new(source.value.syntax()),
-            name_ptr: AstPtr::new(&name_node),
+            name_ptr: AstPtr::new(&name_node).wrap_left(),
         };
 
         if let Some(attrs) = def.attrs(self.db) {
             for alias in attrs.doc_aliases() {
-                self.symbols.push(FileSymbol {
-                    name: alias.as_str().into(),
+                self.symbols.insert(FileSymbol {
+                    name: alias.clone(),
                     def,
                     loc: dec_loc.clone(),
                     container_name: self.current_container_name.clone(),
@@ -303,8 +388,8 @@ impl<'a> SymbolCollector<'a> {
             }
         }
 
-        self.symbols.push(FileSymbol {
-            name: name_node.text().into(),
+        self.symbols.insert(FileSymbol {
+            name: name.symbol().clone(),
             def,
             container_name: self.current_container_name.clone(),
             loc: dec_loc,
@@ -313,7 +398,7 @@ impl<'a> SymbolCollector<'a> {
         });
     }
 
-    fn push_module(&mut self, module_id: ModuleId) {
+    fn push_module(&mut self, module_id: ModuleId, name: &Name) {
         let def_map = module_id.def_map(self.db.upcast());
         let module_data = &def_map[module_id.local_id];
         let Some(declaration) = module_data.origin.declaration() else { return };
@@ -322,15 +407,15 @@ impl<'a> SymbolCollector<'a> {
         let dec_loc = DeclarationLocation {
             hir_file_id: declaration.file_id,
             ptr: SyntaxNodePtr::new(module.syntax()),
-            name_ptr: AstPtr::new(&name_node),
+            name_ptr: AstPtr::new(&name_node).wrap_left(),
         };
 
         let def = ModuleDef::Module(module_id.into());
 
         if let Some(attrs) = def.attrs(self.db) {
             for alias in attrs.doc_aliases() {
-                self.symbols.push(FileSymbol {
-                    name: alias.as_str().into(),
+                self.symbols.insert(FileSymbol {
+                    name: alias.clone(),
                     def,
                     loc: dec_loc.clone(),
                     container_name: self.current_container_name.clone(),
@@ -340,8 +425,8 @@ impl<'a> SymbolCollector<'a> {
             }
         }
 
-        self.symbols.push(FileSymbol {
-            name: name_node.text().into(),
+        self.symbols.insert(FileSymbol {
+            name: name.symbol().clone(),
             def: ModuleDef::Module(module_id.into()),
             container_name: self.current_container_name.clone(),
             loc: dec_loc,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs b/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs
index 074d943719f..64e77b2d698 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs
@@ -109,6 +109,10 @@ impl<'a> AssistContext<'a> {
         self.trimmed_range
     }
 
+    pub(crate) fn source_file(&self) -> &SourceFile {
+        &self.source_file
+    }
+
     pub(crate) fn token_at_offset(&self) -> TokenAtOffset<SyntaxToken> {
         self.source_file.syntax().token_at_offset(self.offset())
     }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
index 24b34f140bd..5899ec5a005 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
@@ -212,8 +212,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
                     !hidden
                 })
                 .map(|(pat, _)| {
-                    make::match_arm(iter::once(pat), None, make::ext::expr_todo())
-                        .clone_for_update()
+                    make::match_arm(pat, None, make::ext::expr_todo()).clone_for_update()
                 });
 
             let catch_all_arm = new_match_arm_list
@@ -243,12 +242,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
 
             if needs_catch_all_arm && !has_catch_all_arm {
                 cov_mark::hit!(added_wildcard_pattern);
-                let arm = make::match_arm(
-                    iter::once(make::wildcard_pat().into()),
-                    None,
-                    make::ext::expr_todo(),
-                )
-                .clone_for_update();
+                let arm =
+                    make::match_arm(make::wildcard_pat().into(), None, make::ext::expr_todo())
+                        .clone_for_update();
                 todo_placeholders.push(arm.expr().unwrap());
                 added_arms.push(arm);
             }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs
index 62700ab1809..04d63f5bc8f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs
@@ -189,7 +189,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
 /// This will create a turbofish generic arg list corresponding to the number of arguments
 fn get_fish_head(make: &SyntaxFactory, number_of_arguments: usize) -> ast::GenericArgList {
     let args = (0..number_of_arguments).map(|_| make::type_arg(make::ty_placeholder()).into());
-    make.turbofish_generic_arg_list(args)
+    make.generic_arg_list(args, true)
 }
 
 #[cfg(test)]
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 f178a7e0cec..70fb5680052 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
@@ -252,7 +252,7 @@ fn tail_cb_impl(edit: &mut SourceChangeBuilder, e: &ast::Expr) {
 
 /// Add bang and parentheses to the expression.
 fn add_bang_paren(expr: ast::Expr) -> ast::Expr {
-    make::expr_prefix(T![!], make::expr_paren(expr))
+    make::expr_prefix(T![!], make::expr_paren(expr)).into()
 }
 
 #[cfg(test)]
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/bool_to_enum.rs
index f699899066b..cbd39796241 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/bool_to_enum.rs
@@ -195,6 +195,7 @@ fn bool_expr_to_enum_expr(expr: ast::Expr) -> ast::Expr {
             make::tail_only_block_expr(true_expr),
             Some(ast::ElseBranch::Block(make::tail_only_block_expr(false_expr))),
         )
+        .into()
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
index 79f303b37a4..bb04a43cf96 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
@@ -507,7 +507,7 @@ fn wrap_capture_in_deref_if_needed(
     if does_autoderef {
         return capture_name;
     }
-    make::expr_prefix(T![*], capture_name)
+    make::expr_prefix(T![*], capture_name).into()
 }
 
 fn capture_as_arg(ctx: &AssistContext<'_>, capture: &ClosureCapture) -> ast::Expr {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs
index 67c72a93dad..dd2e9cbcb5f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs
@@ -97,7 +97,7 @@ pub(crate) fn convert_from_to_tryfrom(acc: &mut Assists, ctx: &AssistContext<'_>
             );
 
             for r in return_exprs {
-                let t = r.expr().unwrap_or_else(make::expr_unit);
+                let t = r.expr().unwrap_or_else(make::ext::expr_unit);
                 ted::replace(t.syntax(), wrap_ok(t.clone()).syntax().clone_for_update());
             }
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs
index 434daa279ca..0b92beefbcd 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs
@@ -60,7 +60,7 @@ pub(crate) fn convert_while_to_loop(acc: &mut Assists, ctx: &AssistContext<'_>)
             .indent(while_indent_level);
             let block_expr = if is_pattern_cond(while_cond.clone()) {
                 let if_expr = make::expr_if(while_cond, while_body, Some(break_block.into()));
-                let stmts = iter::once(make::expr_stmt(if_expr).into());
+                let stmts = iter::once(make::expr_stmt(if_expr.into()).into());
                 make::block_expr(stmts, None)
             } else {
                 let if_cond = invert_boolean_expression(while_cond);
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
index 7df6ca1565f..39142d60620 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
@@ -1128,7 +1128,10 @@ fn main {
             destructure_tuple_binding_impl(acc, ctx, false)
         }
 
-        pub(crate) fn check_in_place_assist(ra_fixture_before: &str, ra_fixture_after: &str) {
+        pub(crate) fn check_in_place_assist(
+            #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+            #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
+        ) {
             check_assist_by_label(
                 in_place_assist,
                 ra_fixture_before,
@@ -1138,7 +1141,10 @@ fn main {
             );
         }
 
-        pub(crate) fn check_sub_pattern_assist(ra_fixture_before: &str, ra_fixture_after: &str) {
+        pub(crate) fn check_sub_pattern_assist(
+            #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+            #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
+        ) {
             check_assist_by_label(
                 assist,
                 ra_fixture_before,
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 0d1b6af7204..967da41c15f 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
@@ -1533,7 +1533,7 @@ impl FlowHandler {
                     .into(),
                     call_expr,
                 );
-                make::expr_if(condition.into(), block, None)
+                make::expr_if(condition.into(), block, None).into()
             }
             FlowHandler::IfOption { action } => {
                 let path = make::ext::ident_path("Some");
@@ -1544,7 +1544,7 @@ impl FlowHandler {
                 let action_expr = action.make_result_handler(Some(value));
                 let action_stmt = make::expr_stmt(action_expr);
                 let then = make::block_expr(iter::once(action_stmt.into()), None);
-                make::expr_if(cond.into(), then, None)
+                make::expr_if(cond.into(), then, None).into()
             }
             FlowHandler::MatchOption { none } => {
                 let some_name = "value";
@@ -1554,15 +1554,15 @@ impl FlowHandler {
                     let value_pat = make::ext::simple_ident_pat(make::name(some_name));
                     let pat = make::tuple_struct_pat(path, iter::once(value_pat.into()));
                     let value = make::expr_path(make::ext::ident_path(some_name));
-                    make::match_arm(iter::once(pat.into()), None, value)
+                    make::match_arm(pat.into(), None, value)
                 };
                 let none_arm = {
                     let path = make::ext::ident_path("None");
                     let pat = make::path_pat(path);
-                    make::match_arm(iter::once(pat), None, none.make_result_handler(None))
+                    make::match_arm(pat, None, none.make_result_handler(None))
                 };
                 let arms = make::match_arm_list(vec![some_arm, none_arm]);
-                make::expr_match(call_expr, arms)
+                make::expr_match(call_expr, arms).into()
             }
             FlowHandler::MatchResult { err } => {
                 let ok_name = "value";
@@ -1573,21 +1573,17 @@ impl FlowHandler {
                     let value_pat = make::ext::simple_ident_pat(make::name(ok_name));
                     let pat = make::tuple_struct_pat(path, iter::once(value_pat.into()));
                     let value = make::expr_path(make::ext::ident_path(ok_name));
-                    make::match_arm(iter::once(pat.into()), None, value)
+                    make::match_arm(pat.into(), None, value)
                 };
                 let err_arm = {
                     let path = make::ext::ident_path("Err");
                     let value_pat = make::ext::simple_ident_pat(make::name(err_name));
                     let pat = make::tuple_struct_pat(path, iter::once(value_pat.into()));
                     let value = make::expr_path(make::ext::ident_path(err_name));
-                    make::match_arm(
-                        iter::once(pat.into()),
-                        None,
-                        err.make_result_handler(Some(value)),
-                    )
+                    make::match_arm(pat.into(), None, err.make_result_handler(Some(value)))
                 };
                 let arms = make::match_arm_list(vec![ok_arm, err_arm]);
-                make::expr_match(call_expr, arms)
+                make::expr_match(call_expr, arms).into()
             }
         }
     }
@@ -1879,7 +1875,7 @@ fn make_body(ctx: &AssistContext<'_>, old_indent: IndentLevel, fun: &Function) -
                             .iter()
                             .map(|var| path_expr_from_local(ctx, var.local, fun.mods.edition));
                         let expr = make::expr_tuple(exprs);
-                        tail_expr = Some(expr);
+                        tail_expr = Some(expr.into());
                     }
                 },
             };
@@ -1910,7 +1906,7 @@ fn make_body(ctx: &AssistContext<'_>, old_indent: IndentLevel, fun: &Function) -
     match &handler {
         FlowHandler::None => block,
         FlowHandler::Try { kind } => {
-            let block = with_default_tail_expr(block, make::expr_unit());
+            let block = with_default_tail_expr(block, make::ext::expr_unit());
             map_tail_expr(block, |tail_expr| {
                 let constructor = match kind {
                     TryKind::Option => "Some",
@@ -1924,7 +1920,7 @@ fn make_body(ctx: &AssistContext<'_>, old_indent: IndentLevel, fun: &Function) -
         FlowHandler::If { .. } => {
             let controlflow_continue = make::expr_call(
                 make::expr_path(make::path_from_text("ControlFlow::Continue")),
-                make::arg_list(iter::once(make::expr_unit())),
+                make::arg_list([make::ext::expr_unit()]),
             );
             with_tail_expr(block, controlflow_continue)
         }
@@ -2127,17 +2123,17 @@ fn make_rewritten_flow(handler: &FlowHandler, arg_expr: Option<ast::Expr>) -> Op
         FlowHandler::None | FlowHandler::Try { .. } => return None,
         FlowHandler::If { .. } => make::expr_call(
             make::expr_path(make::path_from_text("ControlFlow::Break")),
-            make::arg_list(iter::once(make::expr_unit())),
+            make::arg_list([make::ext::expr_unit()]),
         ),
         FlowHandler::IfOption { .. } => {
-            let expr = arg_expr.unwrap_or_else(|| make::expr_tuple(Vec::new()));
-            let args = make::arg_list(iter::once(expr));
+            let expr = arg_expr.unwrap_or_else(make::ext::expr_unit);
+            let args = make::arg_list([expr]);
             make::expr_call(make::expr_path(make::ext::ident_path("Some")), args)
         }
         FlowHandler::MatchOption { .. } => make::expr_path(make::ext::ident_path("None")),
         FlowHandler::MatchResult { .. } => {
-            let expr = arg_expr.unwrap_or_else(|| make::expr_tuple(Vec::new()));
-            let args = make::arg_list(iter::once(expr));
+            let expr = arg_expr.unwrap_or_else(make::ext::expr_unit);
+            let args = make::arg_list([expr]);
             make::expr_call(make::expr_path(make::ext::ident_path("Err")), args)
         }
     };
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
index 0cc807aff64..97321f4ec1e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
@@ -4,6 +4,7 @@ use ide_db::{
     syntax_helpers::{suggest_name, LexedStr},
 };
 use syntax::{
+    algo::ancestors_at_offset,
     ast::{
         self, edit::IndentLevel, edit_in_place::Indent, make, syntax_factory::SyntaxFactory,
         AstNode,
@@ -68,7 +69,10 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
     let node = if ctx.has_empty_selection() {
         if let Some(t) = ctx.token_at_offset().find(|it| it.kind() == T![;]) {
             t.parent().and_then(ast::ExprStmt::cast)?.syntax().clone()
-        } else if let Some(expr) = ctx.find_node_at_offset::<ast::Expr>() {
+        } else if let Some(expr) = ancestors_at_offset(ctx.source_file().syntax(), ctx.offset())
+            .next()
+            .and_then(ast::Expr::cast)
+        {
             expr.syntax().ancestors().find_map(valid_target_expr)?.syntax().clone()
         } else {
             return None;
@@ -469,11 +473,11 @@ mod tests {
             extract_variable,
             r#"
 fn main() -> i32 {
-    if true {
+    if$0 true {
         1
     } else {
         2
-    }$0
+    }
 }
 "#,
             r#"
@@ -581,11 +585,11 @@ fn main() {
             extract_variable,
             r#"
 fn main() -> i32 {
-    if true {
+    if$0 true {
         1
     } else {
         2
-    }$0
+    }
 }
 "#,
             r#"
@@ -676,11 +680,11 @@ fn main() {
             extract_variable,
             r#"
 fn main() -> i32 {
-    if true {
+    if$0 true {
         1
     } else {
         2
-    }$0
+    }
 }
 "#,
             r#"
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 c879a4a3d95..ac58af62525 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
@@ -933,7 +933,7 @@ mod tests_setter {
 
     use super::*;
 
-    fn check_not_applicable(ra_fixture: &str) {
+    fn check_not_applicable(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         check_assist_not_applicable(generate_setter, ra_fixture)
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs
index d558ec3bec7..cd6f900ba15 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs
@@ -38,21 +38,21 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
 pub(crate) fn inline_macro(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let unexpanded = ctx.find_node_at_offset::<ast::MacroCall>()?;
     let macro_call = ctx.sema.to_def(&unexpanded)?;
-    let expanded = ctx.sema.parse_or_expand(macro_call.as_file());
-    let span_map = ctx.sema.db.expansion_span_map(macro_call.as_macro_file());
-    let expanded = prettify_macro_expansion(
-        ctx.db(),
-        expanded,
-        &span_map,
-        ctx.sema.file_to_module_def(ctx.file_id())?.krate().into(),
-    );
+    let target_crate_id = ctx.sema.file_to_module_def(ctx.file_id())?.krate().into();
     let text_range = unexpanded.syntax().text_range();
 
     acc.add(
         AssistId("inline_macro", AssistKind::RefactorInline),
         "Inline macro".to_owned(),
         text_range,
-        |builder| builder.replace(text_range, expanded.to_string()),
+        |builder| {
+            let expanded = ctx.sema.parse_or_expand(macro_call.as_file());
+            let span_map = ctx.sema.db.expansion_span_map(macro_call.as_macro_file());
+            // Don't call `prettify_macro_expansion()` outside the actual assist action; it does some heavy rowan tree manipulation,
+            // which can be very costly for big macros when it is done *even without the assist being invoked*.
+            let expanded = prettify_macro_expansion(ctx.db(), expanded, &span_map, target_crate_id);
+            builder.replace(text_range, expanded.to_string())
+        },
     )
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs
index f0c96fe3cb8..a487960d8d4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs
@@ -61,7 +61,7 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext<'_>)
             };
 
             edit.delete(guard.syntax().text_range());
-            edit.replace_ast(arm_expr, if_expr);
+            edit.replace_ast(arm_expr, if_expr.into());
         },
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
index 94274f6d17c..1f57f7d3d37 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
@@ -102,7 +102,7 @@ fn compute_dbg_replacement(macro_expr: ast::MacroExpr) -> Option<(TextRange, Opt
                         };
                         (range, None)
                     },
-                    _ => (macro_call.syntax().text_range(), Some(make::expr_unit())),
+                    _ => (macro_call.syntax().text_range(), Some(make::ext::expr_unit())),
                 }
             }
         }
@@ -152,7 +152,7 @@ fn compute_dbg_replacement(macro_expr: ast::MacroExpr) -> Option<(TextRange, Opt
         exprs => {
             let exprs = exprs.iter().cloned().map(replace_nested_dbgs);
             let expr = make::expr_tuple(exprs);
-            (macro_call.syntax().text_range(), Some(expr))
+            (macro_call.syntax().text_range(), Some(expr.into()))
         }
     })
 }
@@ -209,7 +209,10 @@ mod tests {
 
     use super::*;
 
-    fn check(ra_fixture_before: &str, ra_fixture_after: &str) {
+    fn check(
+        #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+        #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
+    ) {
         check_assist(
             remove_dbg,
             &format!("fn main() {{\n{ra_fixture_before}\n}}"),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
index b31d45e6d45..e324d6eaaad 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
@@ -1,4 +1,4 @@
-use std::iter::{self, successors};
+use std::iter::successors;
 
 use either::Either;
 use ide_db::{
@@ -8,11 +8,7 @@ use ide_db::{
     RootDatabase,
 };
 use syntax::{
-    ast::{
-        self,
-        edit::{AstNodeEdit, IndentLevel},
-        make, HasName,
-    },
+    ast::{self, edit::IndentLevel, edit_in_place::Indent, syntax_factory::SyntaxFactory, HasName},
     AstNode, TextRange, T,
 };
 
@@ -108,53 +104,58 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<'
         AssistId("replace_if_let_with_match", AssistKind::RefactorRewrite),
         format!("Replace if{let_} with match"),
         available_range,
-        move |edit| {
+        move |builder| {
+            let make = SyntaxFactory::new();
             let match_expr = {
-                let else_arm = make_else_arm(ctx, else_block, &cond_bodies);
+                let else_arm = make_else_arm(ctx, &make, else_block, &cond_bodies);
                 let make_match_arm = |(pat, body): (_, ast::BlockExpr)| {
-                    let body = body.reset_indent().indent(IndentLevel(1));
+                    let body = make.block_expr(body.statements(), body.tail_expr());
+                    body.indent(IndentLevel::from(1));
+                    let body = unwrap_trivial_block(body);
                     match pat {
-                        Either::Left(pat) => {
-                            make::match_arm(iter::once(pat), None, unwrap_trivial_block(body))
+                        Either::Left(pat) => make.match_arm(pat, None, body),
+                        Either::Right(_) if !pat_seen => {
+                            make.match_arm(make.literal_pat("true").into(), None, body)
                         }
-                        Either::Right(_) if !pat_seen => make::match_arm(
-                            iter::once(make::literal_pat("true").into()),
-                            None,
-                            unwrap_trivial_block(body),
-                        ),
-                        Either::Right(expr) => make::match_arm(
-                            iter::once(make::wildcard_pat().into()),
-                            Some(expr),
-                            unwrap_trivial_block(body),
+                        Either::Right(expr) => make.match_arm(
+                            make.wildcard_pat().into(),
+                            Some(make.match_guard(expr)),
+                            body,
                         ),
                     }
                 };
-                let arms = cond_bodies.into_iter().map(make_match_arm).chain(iter::once(else_arm));
-                let match_expr = make::expr_match(scrutinee_to_be_expr, make::match_arm_list(arms));
-                match_expr.indent(IndentLevel::from_node(if_expr.syntax()))
+                let arms = cond_bodies.into_iter().map(make_match_arm).chain([else_arm]);
+                let match_expr = make.expr_match(scrutinee_to_be_expr, make.match_arm_list(arms));
+                match_expr.indent(IndentLevel::from_node(if_expr.syntax()));
+                match_expr.into()
             };
 
             let has_preceding_if_expr =
                 if_expr.syntax().parent().is_some_and(|it| ast::IfExpr::can_cast(it.kind()));
             let expr = if has_preceding_if_expr {
                 // make sure we replace the `else if let ...` with a block so we don't end up with `else expr`
-                make::block_expr(None, Some(match_expr)).into()
+                make.block_expr([], Some(match_expr)).into()
             } else {
                 match_expr
             };
-            edit.replace_ast::<ast::Expr>(if_expr.into(), expr);
+
+            let mut editor = builder.make_editor(if_expr.syntax());
+            editor.replace(if_expr.syntax(), expr.syntax());
+            editor.add_mappings(make.finish_with_mappings());
+            builder.add_file_edits(ctx.file_id(), editor);
         },
     )
 }
 
 fn make_else_arm(
     ctx: &AssistContext<'_>,
+    make: &SyntaxFactory,
     else_block: Option<ast::BlockExpr>,
     conditionals: &[(Either<ast::Pat, ast::Expr>, ast::BlockExpr)],
 ) -> ast::MatchArm {
     let (pattern, expr) = if let Some(else_block) = else_block {
         let pattern = match conditionals {
-            [(Either::Right(_), _)] => make::literal_pat("false").into(),
+            [(Either::Right(_), _)] => make.literal_pat("false").into(),
             [(Either::Left(pat), _)] => match ctx
                 .sema
                 .type_of_pat(pat)
@@ -164,24 +165,24 @@ fn make_else_arm(
                     if does_pat_match_variant(pat, &it.sad_pattern()) {
                         it.happy_pattern_wildcard()
                     } else if does_pat_variant_nested_or_literal(ctx, pat) {
-                        make::wildcard_pat().into()
+                        make.wildcard_pat().into()
                     } else {
                         it.sad_pattern()
                     }
                 }
-                None => make::wildcard_pat().into(),
+                None => make.wildcard_pat().into(),
             },
-            _ => make::wildcard_pat().into(),
+            _ => make.wildcard_pat().into(),
         };
         (pattern, unwrap_trivial_block(else_block))
     } else {
         let pattern = match conditionals {
-            [(Either::Right(_), _)] => make::literal_pat("false").into(),
-            _ => make::wildcard_pat().into(),
+            [(Either::Right(_), _)] => make.literal_pat("false").into(),
+            _ => make.wildcard_pat().into(),
         };
-        (pattern, make::expr_unit())
+        (pattern, make.expr_unit())
     };
-    make::match_arm(iter::once(pattern), None, expr)
+    make.match_arm(pattern, None, expr)
 }
 
 // Assist: replace_match_with_if_let
@@ -247,21 +248,21 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
         }
         _ => " let",
     };
-    let target = match_expr.syntax().text_range();
     acc.add(
         AssistId("replace_match_with_if_let", AssistKind::RefactorRewrite),
         format!("Replace match with if{let_}"),
-        target,
-        move |edit| {
-            fn make_block_expr(expr: ast::Expr) -> ast::BlockExpr {
+        match_expr.syntax().text_range(),
+        move |builder| {
+            let make = SyntaxFactory::new();
+            let make_block_expr = |expr: ast::Expr| {
                 // Blocks with modifiers (unsafe, async, etc.) are parsed as BlockExpr, but are
                 // formatted without enclosing braces. If we encounter such block exprs,
                 // wrap them in another BlockExpr.
                 match expr {
                     ast::Expr::BlockExpr(block) if block.modifier().is_none() => block,
-                    expr => make::block_expr(iter::empty(), Some(expr)),
+                    expr => make.block_expr([], Some(expr)),
                 }
-            }
+            };
 
             let condition = match if_let_pat {
                 ast::Pat::LiteralPat(p)
@@ -272,20 +273,25 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
                 ast::Pat::LiteralPat(p)
                     if p.literal().is_some_and(|it| it.token().kind() == T![false]) =>
                 {
-                    make::expr_prefix(T![!], scrutinee)
+                    make.expr_prefix(T![!], scrutinee).into()
                 }
-                _ => make::expr_let(if_let_pat, scrutinee).into(),
+                _ => make.expr_let(if_let_pat, scrutinee).into(),
             };
-            let then_block = make_block_expr(then_expr.reset_indent());
+            let then_expr = then_expr.clone_for_update();
+            then_expr.reindent_to(IndentLevel::single());
+            let then_block = make_block_expr(then_expr);
             let else_expr = if is_empty_expr(&else_expr) { None } else { Some(else_expr) };
-            let if_let_expr = make::expr_if(
+            let if_let_expr = make.expr_if(
                 condition,
                 then_block,
                 else_expr.map(make_block_expr).map(ast::ElseBranch::Block),
-            )
-            .indent(IndentLevel::from_node(match_expr.syntax()));
+            );
+            if_let_expr.indent(IndentLevel::from_node(match_expr.syntax()));
 
-            edit.replace_ast::<ast::Expr>(match_expr.into(), if_let_expr);
+            let mut editor = builder.make_editor(match_expr.syntax());
+            editor.replace(match_expr.syntax(), if_let_expr.syntax());
+            editor.add_mappings(make.finish_with_mappings());
+            builder.add_file_edits(ctx.file_id(), editor);
         },
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs
index c2be4593b97..c071d3022d2 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs
@@ -1,12 +1,6 @@
-use std::iter::once;
-
 use ide_db::ty_filter::TryEnum;
 use syntax::{
-    ast::{
-        self,
-        edit::{AstNodeEdit, IndentLevel},
-        make,
-    },
+    ast::{self, edit::IndentLevel, edit_in_place::Indent, syntax_factory::SyntaxFactory},
     AstNode, T,
 };
 
@@ -47,7 +41,9 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext<'_>
         AssistId("replace_let_with_if_let", AssistKind::RefactorRewrite),
         "Replace let with if let",
         target,
-        |edit| {
+        |builder| {
+            let mut editor = builder.make_editor(let_stmt.syntax());
+            let make = SyntaxFactory::new();
             let ty = ctx.sema.type_of_expr(&init);
             let happy_variant = ty
                 .and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty.adjusted()))
@@ -55,17 +51,18 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext<'_>
             let pat = match happy_variant {
                 None => original_pat,
                 Some(var_name) => {
-                    make::tuple_struct_pat(make::ext::ident_path(var_name), once(original_pat))
-                        .into()
+                    make.tuple_struct_pat(make.ident_path(var_name), [original_pat]).into()
                 }
             };
 
-            let block =
-                make::ext::empty_block_expr().indent(IndentLevel::from_node(let_stmt.syntax()));
-            let if_ = make::expr_if(make::expr_let(pat, init).into(), block, None);
-            let stmt = make::expr_stmt(if_);
+            let block = make.block_expr([], None);
+            block.indent(IndentLevel::from_node(let_stmt.syntax()));
+            let if_expr = make.expr_if(make.expr_let(pat, init).into(), block, None);
+            let if_stmt = make.expr_stmt(if_expr.into());
 
-            edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt));
+            editor.replace(let_stmt.syntax(), if_stmt.syntax());
+            editor.add_mappings(make.finish_with_mappings());
+            builder.add_file_edits(ctx.file_id(), editor);
         },
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs
index 2e26f59d030..88b50543dda 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs
@@ -71,19 +71,17 @@ pub(crate) fn replace_try_expr_with_match(
             };
 
             let happy_arm = make::match_arm(
-                iter::once(
-                    try_enum.happy_pattern(make::ident_pat(false, false, make::name("it")).into()),
-                ),
+                try_enum.happy_pattern(make::ident_pat(false, false, make::name("it")).into()),
                 None,
                 make::expr_path(make::ext::ident_path("it")),
             );
-            let sad_arm = make::match_arm(iter::once(sad_pat), None, sad_expr);
+            let sad_arm = make::match_arm(sad_pat, None, sad_expr);
 
             let match_arm_list = make::match_arm_list([happy_arm, sad_arm]);
 
             let expr_match = make::expr_match(expr, match_arm_list)
                 .indent(IndentLevel::from_node(qm_kw_parent.syntax()));
-            edit.replace_ast::<ast::Expr>(qm_kw_parent.into(), expr_match);
+            edit.replace_ast::<ast::Expr>(qm_kw_parent.into(), expr_match.into());
         },
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs
index c6cffb5434a..6b9f661d4de 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs
@@ -54,13 +54,9 @@ pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
             let pats_after = pipe_token
                 .siblings_with_tokens(Direction::Next)
                 .filter_map(|it| ast::Pat::cast(it.into_node()?));
-            // FIXME: We should add a leading pipe if the original arm has one.
-            let new_match_arm = make::match_arm(
-                pats_after,
-                match_arm.guard().and_then(|guard| guard.condition()),
-                match_arm_body,
-            )
-            .clone_for_update();
+            let new_pat = make::or_pat(pats_after, or_pat.leading_pipe().is_some());
+            let new_match_arm =
+                make::match_arm(new_pat, match_arm.guard(), match_arm_body).clone_for_update();
 
             let mut pipe_index = pipe_token.index();
             if pipe_token
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs
index f3e7f5f4167..fd37140e9c2 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs
@@ -61,7 +61,7 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
                 }
             }
             None => {
-                let empty_tuple = make::expr_tuple([]);
+                let empty_tuple = make::ext::expr_unit();
                 make::let_stmt(pattern, ty, Some(empty_tuple)).to_string()
             }
         };
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs
index 64d5e2c9b82..f647b531b77 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs
@@ -1,11 +1,11 @@
+use either::Either;
 use ide_db::{
     famous_defs::FamousDefs,
     syntax_helpers::node_ext::{for_each_tail_expr, walk_expr},
 };
-use itertools::Itertools;
 use syntax::{
-    ast::{self, Expr, HasGenericArgs},
-    match_ast, AstNode, NodeOrToken, SyntaxKind, TextRange,
+    ast::{self, syntax_factory::SyntaxFactory, HasArgList, HasGenericArgs},
+    match_ast, AstNode, NodeOrToken, SyntaxKind,
 };
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
@@ -39,11 +39,11 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
 pub(crate) fn unwrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let ret_type = ctx.find_node_at_offset::<ast::RetType>()?;
     let parent = ret_type.syntax().parent()?;
-    let body = match_ast! {
+    let body_expr = match_ast! {
         match parent {
-            ast::Fn(func) => func.body()?,
+            ast::Fn(func) => func.body()?.into(),
             ast::ClosureExpr(closure) => match closure.body()? {
-                Expr::BlockExpr(block) => block,
+                ast::Expr::BlockExpr(block) => block.into(),
                 // closures require a block when a return type is specified
                 _ => return None,
             },
@@ -65,72 +65,110 @@ pub(crate) fn unwrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) ->
     let happy_type = extract_wrapped_type(type_ref)?;
 
     acc.add(kind.assist_id(), kind.label(), type_ref.syntax().text_range(), |builder| {
-        let body = ast::Expr::BlockExpr(body);
+        let mut editor = builder.make_editor(&parent);
+        let make = SyntaxFactory::new();
 
         let mut exprs_to_unwrap = Vec::new();
         let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_unwrap, e);
-        walk_expr(&body, &mut |expr| {
-            if let Expr::ReturnExpr(ret_expr) = expr {
+        walk_expr(&body_expr, &mut |expr| {
+            if let ast::Expr::ReturnExpr(ret_expr) = expr {
                 if let Some(ret_expr_arg) = &ret_expr.expr() {
                     for_each_tail_expr(ret_expr_arg, tail_cb);
                 }
             }
         });
-        for_each_tail_expr(&body, tail_cb);
+        for_each_tail_expr(&body_expr, tail_cb);
 
         let is_unit_type = is_unit_type(&happy_type);
         if is_unit_type {
-            let mut text_range = ret_type.syntax().text_range();
-
             if let Some(NodeOrToken::Token(token)) = ret_type.syntax().next_sibling_or_token() {
                 if token.kind() == SyntaxKind::WHITESPACE {
-                    text_range = TextRange::new(text_range.start(), token.text_range().end());
+                    editor.delete(token);
                 }
             }
 
-            builder.delete(text_range);
+            editor.delete(ret_type.syntax());
         } else {
-            builder.replace(type_ref.syntax().text_range(), happy_type.syntax().text());
+            editor.replace(type_ref.syntax(), happy_type.syntax());
         }
 
-        for ret_expr_arg in exprs_to_unwrap {
-            let ret_expr_str = ret_expr_arg.to_string();
-
-            let needs_replacing = match kind {
-                UnwrapperKind::Option => ret_expr_str.starts_with("Some("),
-                UnwrapperKind::Result => {
-                    ret_expr_str.starts_with("Ok(") || ret_expr_str.starts_with("Err(")
-                }
-            };
+        let mut final_placeholder = None;
+        for tail_expr in exprs_to_unwrap {
+            match &tail_expr {
+                ast::Expr::CallExpr(call_expr) => {
+                    let ast::Expr::PathExpr(path_expr) = call_expr.expr().unwrap() else {
+                        continue;
+                    };
+
+                    let path_str = path_expr.path().unwrap().to_string();
+                    let needs_replacing = match kind {
+                        UnwrapperKind::Option => path_str == "Some",
+                        UnwrapperKind::Result => path_str == "Ok" || path_str == "Err",
+                    };
+
+                    if !needs_replacing {
+                        continue;
+                    }
 
-            if needs_replacing {
-                let arg_list = ret_expr_arg.syntax().children().find_map(ast::ArgList::cast);
-                if let Some(arg_list) = arg_list {
+                    let arg_list = call_expr.arg_list().unwrap();
                     if is_unit_type {
-                        match ret_expr_arg.syntax().prev_sibling_or_token() {
-                            // Useful to delete the entire line without leaving trailing whitespaces
-                            Some(whitespace) => {
-                                let new_range = TextRange::new(
-                                    whitespace.text_range().start(),
-                                    ret_expr_arg.syntax().text_range().end(),
-                                );
-                                builder.delete(new_range);
+                        let tail_parent = tail_expr
+                            .syntax()
+                            .parent()
+                            .and_then(Either::<ast::ReturnExpr, ast::StmtList>::cast)
+                            .unwrap();
+                        match tail_parent {
+                            Either::Left(ret_expr) => {
+                                editor.replace(ret_expr.syntax(), make.expr_return(None).syntax())
                             }
-                            None => {
-                                builder.delete(ret_expr_arg.syntax().text_range());
+                            Either::Right(stmt_list) => {
+                                let new_block = if stmt_list.statements().next().is_none() {
+                                    make.expr_empty_block()
+                                } else {
+                                    make.block_expr(stmt_list.statements(), None)
+                                };
+                                editor.replace(
+                                    stmt_list.syntax(),
+                                    new_block.stmt_list().unwrap().syntax(),
+                                );
                             }
                         }
-                    } else {
-                        builder.replace(
-                            ret_expr_arg.syntax().text_range(),
-                            arg_list.args().join(", "),
+                    } else if let Some(first_arg) = arg_list.args().next() {
+                        editor.replace(tail_expr.syntax(), first_arg.syntax());
+                    }
+                }
+                ast::Expr::PathExpr(path_expr) => {
+                    let UnwrapperKind::Option = kind else {
+                        continue;
+                    };
+
+                    if path_expr.path().unwrap().to_string() != "None" {
+                        continue;
+                    }
+
+                    let new_tail_expr = make.expr_unit();
+                    editor.replace(path_expr.syntax(), new_tail_expr.syntax());
+                    if let Some(cap) = ctx.config.snippet_cap {
+                        editor.add_annotation(
+                            new_tail_expr.syntax(),
+                            builder.make_placeholder_snippet(cap),
                         );
+
+                        final_placeholder = Some(new_tail_expr);
                     }
                 }
-            } else if matches!(kind, UnwrapperKind::Option if ret_expr_str == "None") {
-                builder.replace(ret_expr_arg.syntax().text_range(), "()");
+                _ => (),
             }
         }
+
+        if let Some(cap) = ctx.config.snippet_cap {
+            if let Some(final_placeholder) = final_placeholder {
+                editor.add_annotation(final_placeholder.syntax(), builder.make_tabstop_after(cap));
+            }
+        }
+
+        editor.add_mappings(make.finish_with_mappings());
+        builder.add_file_edits(ctx.file_id(), editor);
     })
 }
 
@@ -168,12 +206,12 @@ impl UnwrapperKind {
 
 fn tail_cb_impl(acc: &mut Vec<ast::Expr>, e: &ast::Expr) {
     match e {
-        Expr::BreakExpr(break_expr) => {
+        ast::Expr::BreakExpr(break_expr) => {
             if let Some(break_expr_arg) = break_expr.expr() {
                 for_each_tail_expr(&break_expr_arg, &mut |e| tail_cb_impl(acc, e))
             }
         }
-        Expr::ReturnExpr(_) => {
+        ast::Expr::ReturnExpr(_) => {
             // all return expressions have already been handled by the walk loop
         }
         e => acc.push(e.clone()),
@@ -238,8 +276,7 @@ fn foo() -> Option<()$0> {
 }
 "#,
             r#"
-fn foo() {
-}
+fn foo() {}
 "#,
             "Unwrap Option return type",
         );
@@ -254,8 +291,7 @@ fn foo() -> Option<()$0>{
 }
 "#,
             r#"
-fn foo() {
-}
+fn foo() {}
 "#,
             "Unwrap Option return type",
         );
@@ -280,7 +316,42 @@ fn foo() -> i32 {
     if true {
         42
     } else {
-        ()
+        ${1:()}$0
+    }
+}
+"#,
+            "Unwrap Option return type",
+        );
+    }
+
+    #[test]
+    fn unwrap_option_return_type_multi_none() {
+        check_assist_by_label(
+            unwrap_return_type,
+            r#"
+//- minicore: option
+fn foo() -> Option<i3$02> {
+    if false {
+        return None;
+    }
+
+    if true {
+        Some(42)
+    } else {
+        None
+    }
+}
+"#,
+            r#"
+fn foo() -> i32 {
+    if false {
+        return ${1:()};
+    }
+
+    if true {
+        42
+    } else {
+        ${2:()}$0
     }
 }
 "#,
@@ -1262,8 +1333,7 @@ fn foo() -> Result<(), Box<dyn Error$0>> {
 }
 "#,
             r#"
-fn foo() {
-}
+fn foo() {}
 "#,
             "Unwrap Result return type",
         );
@@ -1278,8 +1348,7 @@ fn foo() -> Result<(), Box<dyn Error$0>>{
 }
 "#,
             r#"
-fn foo() {
-}
+fn foo() {}
 "#,
             "Unwrap Result return type",
         );
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs
index 658600cd2d0..0b145dcb06b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs
@@ -6,10 +6,9 @@ use ide_db::{
     famous_defs::FamousDefs,
     syntax_helpers::node_ext::{for_each_tail_expr, walk_expr},
 };
-use itertools::Itertools;
 use syntax::{
-    ast::{self, make, Expr, HasGenericParams},
-    match_ast, ted, AstNode, ToSmolStr,
+    ast::{self, syntax_factory::SyntaxFactory, Expr, HasGenericArgs, HasGenericParams},
+    match_ast, AstNode,
 };
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
@@ -43,11 +42,11 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
 pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let ret_type = ctx.find_node_at_offset::<ast::RetType>()?;
     let parent = ret_type.syntax().parent()?;
-    let body = match_ast! {
+    let body_expr = match_ast! {
         match parent {
-            ast::Fn(func) => func.body()?,
+            ast::Fn(func) => func.body()?.into(),
             ast::ClosureExpr(closure) => match closure.body()? {
-                Expr::BlockExpr(block) => block,
+                Expr::BlockExpr(block) => block.into(),
                 // closures require a block when a return type is specified
                 _ => return None,
             },
@@ -75,56 +74,65 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
             kind.assist_id(),
             kind.label(),
             type_ref.syntax().text_range(),
-            |edit| {
-                let alias = wrapper_alias(ctx, &core_wrapper, type_ref, kind.symbol());
-                let new_return_ty =
-                    alias.unwrap_or_else(|| kind.wrap_type(type_ref)).clone_for_update();
-
-                let body = edit.make_mut(ast::Expr::BlockExpr(body.clone()));
+            |builder| {
+                let mut editor = builder.make_editor(&parent);
+                let make = SyntaxFactory::new();
+                let alias = wrapper_alias(ctx, &make, &core_wrapper, type_ref, kind.symbol());
+                let new_return_ty = alias.unwrap_or_else(|| match kind {
+                    WrapperKind::Option => make.ty_option(type_ref.clone()),
+                    WrapperKind::Result => make.ty_result(type_ref.clone(), make.ty_infer().into()),
+                });
 
                 let mut exprs_to_wrap = Vec::new();
                 let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_wrap, e);
-                walk_expr(&body, &mut |expr| {
+                walk_expr(&body_expr, &mut |expr| {
                     if let Expr::ReturnExpr(ret_expr) = expr {
                         if let Some(ret_expr_arg) = &ret_expr.expr() {
                             for_each_tail_expr(ret_expr_arg, tail_cb);
                         }
                     }
                 });
-                for_each_tail_expr(&body, tail_cb);
+                for_each_tail_expr(&body_expr, tail_cb);
 
                 for ret_expr_arg in exprs_to_wrap {
-                    let happy_wrapped = make::expr_call(
-                        make::expr_path(make::ext::ident_path(kind.happy_ident())),
-                        make::arg_list(iter::once(ret_expr_arg.clone())),
-                    )
-                    .clone_for_update();
-                    ted::replace(ret_expr_arg.syntax(), happy_wrapped.syntax());
+                    let happy_wrapped = make.expr_call(
+                        make.expr_path(make.ident_path(kind.happy_ident())),
+                        make.arg_list(iter::once(ret_expr_arg.clone())),
+                    );
+                    editor.replace(ret_expr_arg.syntax(), happy_wrapped.syntax());
                 }
 
-                let old_return_ty = edit.make_mut(type_ref.clone());
-                ted::replace(old_return_ty.syntax(), new_return_ty.syntax());
+                editor.replace(type_ref.syntax(), new_return_ty.syntax());
 
                 if let WrapperKind::Result = kind {
                     // Add a placeholder snippet at the first generic argument that doesn't equal the return type.
                     // This is normally the error type, but that may not be the case when we inserted a type alias.
-                    let args =
-                        new_return_ty.syntax().descendants().find_map(ast::GenericArgList::cast);
-                    let error_type_arg = args.and_then(|list| {
-                        list.generic_args().find(|arg| match arg {
-                            ast::GenericArg::TypeArg(_) => {
-                                arg.syntax().text() != type_ref.syntax().text()
-                            }
-                            ast::GenericArg::LifetimeArg(_) => false,
-                            _ => true,
-                        })
+                    let args = new_return_ty
+                        .path()
+                        .unwrap()
+                        .segment()
+                        .unwrap()
+                        .generic_arg_list()
+                        .unwrap();
+                    let error_type_arg = args.generic_args().find(|arg| match arg {
+                        ast::GenericArg::TypeArg(_) => {
+                            arg.syntax().text() != type_ref.syntax().text()
+                        }
+                        ast::GenericArg::LifetimeArg(_) => false,
+                        _ => true,
                     });
                     if let Some(error_type_arg) = error_type_arg {
                         if let Some(cap) = ctx.config.snippet_cap {
-                            edit.add_placeholder_snippet(cap, error_type_arg);
+                            editor.add_annotation(
+                                error_type_arg.syntax(),
+                                builder.make_placeholder_snippet(cap),
+                            );
                         }
                     }
                 }
+
+                editor.add_mappings(make.finish_with_mappings());
+                builder.add_file_edits(ctx.file_id(), editor);
             },
         );
     }
@@ -176,22 +184,16 @@ impl WrapperKind {
             WrapperKind::Result => hir::sym::Result.clone(),
         }
     }
-
-    fn wrap_type(&self, type_ref: &ast::Type) -> ast::Type {
-        match self {
-            WrapperKind::Option => make::ext::ty_option(type_ref.clone()),
-            WrapperKind::Result => make::ext::ty_result(type_ref.clone(), make::ty_placeholder()),
-        }
-    }
 }
 
 // Try to find an wrapper type alias in the current scope (shadowing the default).
 fn wrapper_alias(
     ctx: &AssistContext<'_>,
+    make: &SyntaxFactory,
     core_wrapper: &hir::Enum,
     ret_type: &ast::Type,
     wrapper: hir::Symbol,
-) -> Option<ast::Type> {
+) -> Option<ast::PathType> {
     let wrapper_path = hir::ModPath::from_segments(
         hir::PathKind::Plain,
         iter::once(hir::Name::new_symbol_root(wrapper)),
@@ -207,25 +209,28 @@ fn wrapper_alias(
         })
         .find_map(|alias| {
             let mut inserted_ret_type = false;
-            let generic_params = alias
-                .source(ctx.db())?
-                .value
-                .generic_param_list()?
-                .generic_params()
-                .map(|param| match param {
-                    // Replace the very first type parameter with the functions return type.
-                    ast::GenericParam::TypeParam(_) if !inserted_ret_type => {
-                        inserted_ret_type = true;
-                        ret_type.to_smolstr()
+            let generic_args =
+                alias.source(ctx.db())?.value.generic_param_list()?.generic_params().map(|param| {
+                    match param {
+                        // Replace the very first type parameter with the function's return type.
+                        ast::GenericParam::TypeParam(_) if !inserted_ret_type => {
+                            inserted_ret_type = true;
+                            make.type_arg(ret_type.clone()).into()
+                        }
+                        ast::GenericParam::LifetimeParam(_) => {
+                            make.lifetime_arg(make.lifetime("'_")).into()
+                        }
+                        _ => make.type_arg(make.ty_infer().into()).into(),
                     }
-                    ast::GenericParam::LifetimeParam(_) => make::lifetime("'_").to_smolstr(),
-                    _ => make::ty_placeholder().to_smolstr(),
-                })
-                .join(", ");
+                });
 
             let name = alias.name(ctx.db());
-            let name = name.as_str();
-            Some(make::ty(&format!("{name}<{generic_params}>")))
+            let generic_arg_list = make.generic_arg_list(generic_args, false);
+            let path = make.path_unqualified(
+                make.path_segment_generics(make.name_ref(name.as_str()), generic_arg_list),
+            );
+
+            Some(make.ty_path(path))
         })
     })
 }
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 0b1ff87c5c2..48d2af6d3ff 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
@@ -77,7 +77,11 @@ pub(crate) fn with_single_file(text: &str) -> (RootDatabase, EditionedFileId) {
 }
 
 #[track_caller]
-pub(crate) fn check_assist(assist: Handler, ra_fixture_before: &str, ra_fixture_after: &str) {
+pub(crate) fn check_assist(
+    assist: Handler,
+    #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
+) {
     let ra_fixture_after = trim_indent(ra_fixture_after);
     check(assist, ra_fixture_before, ExpectedResult::After(&ra_fixture_after), None);
 }
@@ -85,8 +89,8 @@ pub(crate) fn check_assist(assist: Handler, ra_fixture_before: &str, ra_fixture_
 #[track_caller]
 pub(crate) fn check_assist_no_snippet_cap(
     assist: Handler,
-    ra_fixture_before: &str,
-    ra_fixture_after: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
 ) {
     let ra_fixture_after = trim_indent(ra_fixture_after);
     check_with_config(
@@ -101,8 +105,8 @@ pub(crate) fn check_assist_no_snippet_cap(
 #[track_caller]
 pub(crate) fn check_assist_import_one(
     assist: Handler,
-    ra_fixture_before: &str,
-    ra_fixture_after: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
 ) {
     let ra_fixture_after = trim_indent(ra_fixture_after);
     check_with_config(
@@ -118,8 +122,8 @@ pub(crate) fn check_assist_import_one(
 // so this is here to allow you choose.
 pub(crate) fn check_assist_by_label(
     assist: Handler,
-    ra_fixture_before: &str,
-    ra_fixture_after: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
     label: &str,
 ) {
     let ra_fixture_after = trim_indent(ra_fixture_after);
@@ -130,22 +134,36 @@ pub(crate) fn check_assist_by_label(
 // `extract_ranges` and mark the target as `<target> </target>` in the
 // fixture?
 #[track_caller]
-pub(crate) fn check_assist_target(assist: Handler, ra_fixture: &str, target: &str) {
+pub(crate) fn check_assist_target(
+    assist: Handler,
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    target: &str,
+) {
     check(assist, ra_fixture, ExpectedResult::Target(target), None);
 }
 
 #[track_caller]
-pub(crate) fn check_assist_not_applicable(assist: Handler, ra_fixture: &str) {
+pub(crate) fn check_assist_not_applicable(
+    assist: Handler,
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+) {
     check(assist, ra_fixture, ExpectedResult::NotApplicable, None);
 }
 
 #[track_caller]
-pub(crate) fn check_assist_not_applicable_by_label(assist: Handler, ra_fixture: &str, label: &str) {
+pub(crate) fn check_assist_not_applicable_by_label(
+    assist: Handler,
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    label: &str,
+) {
     check(assist, ra_fixture, ExpectedResult::NotApplicable, Some(label));
 }
 
 #[track_caller]
-pub(crate) fn check_assist_not_applicable_for_import_one(assist: Handler, ra_fixture: &str) {
+pub(crate) fn check_assist_not_applicable_for_import_one(
+    assist: Handler,
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+) {
     check_with_config(
         TEST_CONFIG_IMPORT_ONE,
         assist,
@@ -157,7 +175,10 @@ pub(crate) fn check_assist_not_applicable_for_import_one(assist: Handler, ra_fix
 
 /// Check assist in unresolved state. Useful to check assists for lazy computation.
 #[track_caller]
-pub(crate) fn check_assist_unresolved(assist: Handler, ra_fixture: &str) {
+pub(crate) fn check_assist_unresolved(
+    assist: Handler,
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+) {
     check(assist, ra_fixture, ExpectedResult::Unresolved, None);
 }
 
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 e20c4ef09e8..78ff4417913 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
@@ -246,7 +246,7 @@ pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize {
 }
 
 pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr {
-    invert_special_case(&expr).unwrap_or_else(|| make::expr_prefix(T![!], expr))
+    invert_special_case(&expr).unwrap_or_else(|| make::expr_prefix(T![!], expr).into())
 }
 
 fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
@@ -262,7 +262,7 @@ fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
                 T![>] => T![<=],
                 T![>=] => T![<],
                 // Parenthesize other expressions before prefixing `!`
-                _ => return Some(make::expr_prefix(T![!], make::expr_paren(expr.clone()))),
+                _ => return Some(make::expr_prefix(T![!], make::expr_paren(expr.clone())).into()),
             };
             ted::replace(op_token, make::token(rev_token));
             Some(bin.into())
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs
index 75caf6d49f7..7a9bdfe1ecc 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs
@@ -66,7 +66,7 @@ fn gen_clone_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
                         let pat = make::record_pat(variant_name.clone(), pats.into_iter());
                         let fields = make::record_expr_field_list(fields);
                         let record_expr = make::record_expr(variant_name, fields).into();
-                        arms.push(make::match_arm(Some(pat.into()), None, record_expr));
+                        arms.push(make::match_arm(pat.into(), None, record_expr));
                     }
 
                     // => match self { Self::Name(arg1) => Self::Name(arg1.clone()) }
@@ -84,21 +84,21 @@ fn gen_clone_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
                         let pat = make::tuple_struct_pat(variant_name.clone(), pats.into_iter());
                         let struct_name = make::expr_path(variant_name);
                         let tuple_expr = make::expr_call(struct_name, make::arg_list(fields));
-                        arms.push(make::match_arm(Some(pat.into()), None, tuple_expr));
+                        arms.push(make::match_arm(pat.into(), None, tuple_expr));
                     }
 
                     // => match self { Self::Name => Self::Name }
                     None => {
                         let pattern = make::path_pat(variant_name.clone());
                         let variant_expr = make::expr_path(variant_name);
-                        arms.push(make::match_arm(Some(pattern), None, variant_expr));
+                        arms.push(make::match_arm(pattern, None, variant_expr));
                     }
                 }
             }
 
             let match_target = make::expr_path(make::ext::ident_path("self"));
             let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
-            make::expr_match(match_target, list)
+            make::expr_match(match_target, list).into()
         }
         ast::Adt::Struct(strukt) => {
             match strukt.field_list() {
@@ -190,7 +190,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
 
                         // => MyStruct { fields.. } => f.debug_struct("MyStruct")...finish(),
                         let pat = make::record_pat(variant_name.clone(), pats.into_iter());
-                        arms.push(make::match_arm(Some(pat.into()), None, expr));
+                        arms.push(make::match_arm(pat.into(), None, expr));
                     }
                     Some(ast::FieldList::TupleFieldList(list)) => {
                         // => f.debug_tuple(name)
@@ -223,7 +223,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
 
                         // => MyStruct (fields..) => f.debug_tuple("MyStruct")...finish(),
                         let pat = make::tuple_struct_pat(variant_name.clone(), pats.into_iter());
-                        arms.push(make::match_arm(Some(pat.into()), None, expr));
+                        arms.push(make::match_arm(pat.into(), None, expr));
                     }
                     None => {
                         let fmt_string = make::expr_literal(&(format!("\"{name}\""))).into();
@@ -232,7 +232,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
                         let macro_call = make::expr_macro_call(macro_name, args);
 
                         let variant_name = make::path_pat(variant_name);
-                        arms.push(make::match_arm(Some(variant_name), None, macro_call));
+                        arms.push(make::match_arm(variant_name, None, macro_call));
                     }
                 }
             }
@@ -241,7 +241,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
             let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
             let match_expr = make::expr_match(match_target, list);
 
-            let body = make::block_expr(None, Some(match_expr));
+            let body = make::block_expr(None, Some(match_expr.into()));
             let body = body.indent(ast::edit::IndentLevel(1));
             ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
             Some(())
@@ -485,7 +485,7 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef>) -
                         let tuple = make::tuple_pat(vec![left.into(), right.into()]);
 
                         if let Some(expr) = expr {
-                            arms.push(make::match_arm(Some(tuple.into()), None, expr));
+                            arms.push(make::match_arm(tuple.into(), None, expr));
                         }
                     }
 
@@ -518,7 +518,7 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef>) -
                         let tuple = make::tuple_pat(vec![left.into(), right.into()]);
 
                         if let Some(expr) = expr {
-                            arms.push(make::match_arm(Some(tuple.into()), None, expr));
+                            arms.push(make::match_arm(tuple.into(), None, expr));
                         }
                     }
                     None => continue,
@@ -538,12 +538,12 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef>) -
                         } else {
                             eq_check
                         };
-                        arms.push(make::match_arm(Some(lhs), None, rhs));
+                        arms.push(make::match_arm(lhs, None, rhs));
                     }
 
-                    let match_target = make::expr_tuple(vec![lhs_name, rhs_name]);
+                    let match_target = make::expr_tuple([lhs_name, rhs_name]).into();
                     let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
-                    make::expr_match(match_target, list)
+                    make::expr_match(match_target, list).into()
                 }
             };
 
@@ -599,15 +599,15 @@ fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef>)
         let variant_name =
             make::path_pat(make::ext::path_from_idents(["core", "cmp", "Ordering", "Equal"])?);
         let lhs = make::tuple_struct_pat(make::ext::path_from_idents(["Some"])?, [variant_name]);
-        arms.push(make::match_arm(Some(lhs.into()), None, make::expr_empty_block()));
+        arms.push(make::match_arm(lhs.into(), None, make::expr_empty_block().into()));
 
         arms.push(make::match_arm(
-            [make::ident_pat(false, false, make::name("ord")).into()],
+            make::ident_pat(false, false, make::name("ord")).into(),
             None,
             make::expr_return(Some(make::expr_path(make::ext::ident_path("ord")))),
         ));
         let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
-        Some(make::expr_stmt(make::expr_match(match_target, list)).into())
+        Some(make::expr_stmt(make::expr_match(match_target, list).into()).into())
     }
 
     fn gen_partial_cmp_call(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/ref_field_expr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/ref_field_expr.rs
index e95b291dd71..d434872ea59 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/ref_field_expr.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/ref_field_expr.rs
@@ -121,7 +121,7 @@ impl RefData {
     /// Derefs `expr` and wraps it in parens if necessary
     pub(crate) fn wrap_expr(&self, mut expr: ast::Expr) -> ast::Expr {
         if self.needs_deref {
-            expr = make::expr_prefix(T![*], expr);
+            expr = make::expr_prefix(T![*], expr).into();
         }
 
         if self.needs_parentheses {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
index 414627fbaba..40669c65c57 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
@@ -329,7 +329,7 @@ impl Completions {
         ctx: &CompletionContext<'_>,
         dot_access: &DotAccess,
         func: hir::Function,
-        receiver: Option<hir::Name>,
+        receiver: Option<SmolStr>,
         local_name: Option<hir::Name>,
     ) {
         if !ctx.check_stability(Some(&func.attrs(ctx.db))) {
@@ -475,7 +475,7 @@ impl Completions {
         &mut self,
         ctx: &CompletionContext<'_>,
         dot_access: &DotAccess,
-        receiver: Option<hir::Name>,
+        receiver: Option<SmolStr>,
         field: hir::Field,
         ty: &hir::Type,
     ) {
@@ -533,7 +533,7 @@ impl Completions {
     pub(crate) fn add_tuple_field(
         &mut self,
         ctx: &CompletionContext<'_>,
-        receiver: Option<hir::Name>,
+        receiver: Option<SmolStr>,
         field: usize,
         ty: &hir::Type,
     ) {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
index 26074672ba9..7679d9076de 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
@@ -2,7 +2,7 @@
 
 use std::ops::ControlFlow;
 
-use hir::{sym, HasContainer, ItemContainer, MethodCandidateCallback, Name};
+use hir::{HasContainer, ItemContainer, MethodCandidateCallback, Name};
 use ide_db::FxHashSet;
 use syntax::SmolStr;
 
@@ -25,21 +25,49 @@ pub(crate) fn complete_dot(
         _ => return,
     };
 
+    let is_field_access = matches!(dot_access.kind, DotAccessKind::Field { .. });
+    let is_method_access_with_parens =
+        matches!(dot_access.kind, DotAccessKind::Method { has_parens: true });
+    let traits_in_scope = ctx.traits_in_scope();
+
     // Suggest .await syntax for types that implement Future trait
-    if receiver_ty.impls_into_future(ctx.db) {
+    if let Some(future_output) = receiver_ty.into_future_output(ctx.db) {
+        let await_str = SmolStr::new_static("await");
         let mut item = CompletionItem::new(
             CompletionItemKind::Keyword,
             ctx.source_range(),
-            SmolStr::new_static("await"),
+            await_str.clone(),
             ctx.edition,
         );
         item.detail("expr.await");
         item.add_to(acc, ctx.db);
-    }
 
-    let is_field_access = matches!(dot_access.kind, DotAccessKind::Field { .. });
-    let is_method_access_with_parens =
-        matches!(dot_access.kind, DotAccessKind::Method { has_parens: true });
+        // Completions that skip `.await`, e.g. `.await.foo()`.
+        let dot_access_kind = match &dot_access.kind {
+            DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
+                DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
+            }
+            it @ DotAccessKind::Method { .. } => *it,
+        };
+        let dot_access = DotAccess {
+            receiver: dot_access.receiver.clone(),
+            receiver_ty: Some(hir::TypeInfo { original: future_output.clone(), adjusted: None }),
+            kind: dot_access_kind,
+            ctx: dot_access.ctx,
+        };
+        complete_fields(
+            acc,
+            ctx,
+            &future_output,
+            |acc, field, ty| acc.add_field(ctx, &dot_access, Some(await_str.clone()), field, &ty),
+            |acc, field, ty| acc.add_tuple_field(ctx, Some(await_str.clone()), field, &ty),
+            is_field_access,
+            is_method_access_with_parens,
+        );
+        complete_methods(ctx, &future_output, &traits_in_scope, |func| {
+            acc.add_method(ctx, &dot_access, func, Some(await_str.clone()), None)
+        });
+    }
 
     complete_fields(
         acc,
@@ -50,8 +78,44 @@ pub(crate) fn complete_dot(
         is_field_access,
         is_method_access_with_parens,
     );
+    complete_methods(ctx, receiver_ty, &traits_in_scope, |func| {
+        acc.add_method(ctx, dot_access, func, None, None)
+    });
 
-    complete_methods(ctx, receiver_ty, |func| acc.add_method(ctx, dot_access, func, None, None));
+    // FIXME:
+    // Checking for the existence of `iter()` is complicated in our setup, because we need to substitute
+    // its return type, so we instead check for `<&Self as IntoIterator>::IntoIter`.
+    // Does <&receiver_ty as IntoIterator>::IntoIter` exist? Assume `iter` is valid
+    let iter = receiver_ty
+        .strip_references()
+        .add_reference(hir::Mutability::Shared)
+        .into_iterator_iter(ctx.db)
+        .map(|ty| (ty, SmolStr::new_static("iter()")));
+    // Does <receiver_ty as IntoIterator>::IntoIter` exist?
+    let into_iter = || {
+        receiver_ty
+            .clone()
+            .into_iterator_iter(ctx.db)
+            .map(|ty| (ty, SmolStr::new_static("into_iter()")))
+    };
+    if let Some((iter, iter_sym)) = iter.or_else(into_iter) {
+        // Skip iterators, e.g. complete `.iter().filter_map()`.
+        let dot_access_kind = match &dot_access.kind {
+            DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
+                DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
+            }
+            it @ DotAccessKind::Method { .. } => *it,
+        };
+        let dot_access = DotAccess {
+            receiver: dot_access.receiver.clone(),
+            receiver_ty: Some(hir::TypeInfo { original: iter.clone(), adjusted: None }),
+            kind: dot_access_kind,
+            ctx: dot_access.ctx,
+        };
+        complete_methods(ctx, &iter, &traits_in_scope, |func| {
+            acc.add_method(ctx, &dot_access, func, Some(iter_sym.clone()), None)
+        });
+    }
 }
 
 pub(crate) fn complete_undotted_self(
@@ -94,18 +158,16 @@ pub(crate) fn complete_undotted_self(
                         in_breakable: expr_ctx.in_breakable,
                     },
                 },
-                Some(Name::new_symbol_root(sym::self_.clone())),
+                Some(SmolStr::new_static("self")),
                 field,
                 &ty,
             )
         },
-        |acc, field, ty| {
-            acc.add_tuple_field(ctx, Some(Name::new_symbol_root(sym::self_.clone())), field, &ty)
-        },
+        |acc, field, ty| acc.add_tuple_field(ctx, Some(SmolStr::new_static("self")), field, &ty),
         true,
         false,
     );
-    complete_methods(ctx, &ty, |func| {
+    complete_methods(ctx, &ty, &ctx.traits_in_scope(), |func| {
         acc.add_method(
             ctx,
             &DotAccess {
@@ -118,7 +180,7 @@ pub(crate) fn complete_undotted_self(
                 },
             },
             func,
-            Some(Name::new_symbol_root(sym::self_.clone())),
+            Some(SmolStr::new_static("self")),
             None,
         )
     });
@@ -160,6 +222,7 @@ fn complete_fields(
 fn complete_methods(
     ctx: &CompletionContext<'_>,
     receiver: &hir::Type,
+    traits_in_scope: &FxHashSet<hir::TraitId>,
     f: impl FnMut(hir::Function),
 ) {
     struct Callback<'a, F> {
@@ -205,7 +268,7 @@ fn complete_methods(
     receiver.iterate_method_candidates_split_inherent(
         ctx.db,
         &ctx.scope,
-        &ctx.traits_in_scope(),
+        traits_in_scope,
         Some(ctx.module),
         None,
         Callback { ctx, f, seen_methods: FxHashSet::default() },
@@ -214,25 +277,13 @@ fn complete_methods(
 
 #[cfg(test)]
 mod tests {
-    use expect_test::{expect, Expect};
+    use expect_test::expect;
 
-    use crate::tests::{
-        check_edit, completion_list_no_kw, completion_list_no_kw_with_private_editable,
-    };
-
-    fn check(ra_fixture: &str, expect: Expect) {
-        let actual = completion_list_no_kw(ra_fixture);
-        expect.assert_eq(&actual);
-    }
-
-    fn check_with_private_editable(ra_fixture: &str, expect: Expect) {
-        let actual = completion_list_no_kw_with_private_editable(ra_fixture);
-        expect.assert_eq(&actual);
-    }
+    use crate::tests::{check_edit, check_no_kw, check_with_private_editable};
 
     #[test]
     fn test_struct_field_and_method_completion() {
-        check(
+        check_no_kw(
             r#"
 struct S { foo: u32 }
 impl S {
@@ -249,7 +300,7 @@ fn foo(s: S) { s.$0 }
 
     #[test]
     fn no_unstable_method_on_stable() {
-        check(
+        check_no_kw(
             r#"
 //- /main.rs crate:main deps:std
 fn foo(s: std::S) { s.$0 }
@@ -266,7 +317,7 @@ impl S {
 
     #[test]
     fn unstable_method_on_nightly() {
-        check(
+        check_no_kw(
             r#"
 //- toolchain:nightly
 //- /main.rs crate:main deps:std
@@ -286,7 +337,7 @@ impl S {
 
     #[test]
     fn test_struct_field_completion_self() {
-        check(
+        check_no_kw(
             r#"
 struct S { the_field: (u32,) }
 impl S {
@@ -302,7 +353,7 @@ impl S {
 
     #[test]
     fn test_struct_field_completion_autoderef() {
-        check(
+        check_no_kw(
             r#"
 struct A { the_field: (u32, i32) }
 impl A {
@@ -318,7 +369,7 @@ impl A {
 
     #[test]
     fn test_no_struct_field_completion_for_method_call() {
-        check(
+        check_no_kw(
             r#"
 struct A { the_field: u32 }
 fn foo(a: A) { a.$0() }
@@ -329,7 +380,7 @@ fn foo(a: A) { a.$0() }
 
     #[test]
     fn test_visibility_filtering() {
-        check(
+        check_no_kw(
             r#"
 //- /lib.rs crate:lib new_source_root:local
 pub mod m {
@@ -348,7 +399,7 @@ fn foo(a: lib::m::A) { a.$0 }
             "#]],
         );
 
-        check(
+        check_no_kw(
             r#"
 //- /lib.rs crate:lib new_source_root:library
 pub mod m {
@@ -367,7 +418,7 @@ fn foo(a: lib::m::A) { a.$0 }
             "#]],
         );
 
-        check(
+        check_no_kw(
             r#"
 //- /lib.rs crate:lib new_source_root:library
 pub mod m {
@@ -384,7 +435,7 @@ fn foo(a: lib::m::A) { a.$0 }
             "#]],
         );
 
-        check(
+        check_no_kw(
             r#"
 //- /lib.rs crate:lib new_source_root:local
 pub struct A {}
@@ -402,7 +453,7 @@ fn foo(a: lib::A) { a.$0 }
                 me pub_method() fn(&self)
             "#]],
         );
-        check(
+        check_no_kw(
             r#"
 //- /lib.rs crate:lib new_source_root:library
 pub struct A {}
@@ -524,7 +575,7 @@ fn foo(a: lib::A) { a.$0 }
 
     #[test]
     fn test_local_impls() {
-        check(
+        check_no_kw(
             r#"
 pub struct A {}
 mod m {
@@ -553,7 +604,7 @@ fn foo(a: A) {
 
     #[test]
     fn test_doc_hidden_filtering() {
-        check(
+        check_no_kw(
             r#"
 //- /lib.rs crate:lib deps:dep
 fn foo(a: dep::A) { a.$0 }
@@ -580,7 +631,7 @@ impl A {
 
     #[test]
     fn test_union_field_completion() {
-        check(
+        check_no_kw(
             r#"
 union U { field: u8, other: u16 }
 fn foo(u: U) { u.$0 }
@@ -594,7 +645,7 @@ fn foo(u: U) { u.$0 }
 
     #[test]
     fn test_method_completion_only_fitting_impls() {
-        check(
+        check_no_kw(
             r#"
 struct A<T> {}
 impl A<u32> {
@@ -613,7 +664,7 @@ fn foo(a: A<u32>) { a.$0 }
 
     #[test]
     fn test_trait_method_completion() {
-        check(
+        check_no_kw(
             r#"
 struct A {}
 trait Trait { fn the_method(&self); }
@@ -643,7 +694,7 @@ fn foo(a: A) { a.the_method();$0 }
 
     #[test]
     fn test_trait_method_completion_deduplicated() {
-        check(
+        check_no_kw(
             r"
 struct A {}
 trait Trait { fn the_method(&self); }
@@ -658,7 +709,7 @@ fn foo(a: &A) { a.$0 }
 
     #[test]
     fn completes_trait_method_from_other_module() {
-        check(
+        check_no_kw(
             r"
 struct A {}
 mod m {
@@ -676,7 +727,7 @@ fn foo(a: A) { a.$0 }
 
     #[test]
     fn test_no_non_self_method() {
-        check(
+        check_no_kw(
             r#"
 struct A {}
 impl A {
@@ -692,7 +743,7 @@ fn foo(a: A) {
 
     #[test]
     fn test_tuple_field_completion() {
-        check(
+        check_no_kw(
             r#"
 fn foo() {
    let b = (0, 3.14);
@@ -708,7 +759,7 @@ fn foo() {
 
     #[test]
     fn test_tuple_struct_field_completion() {
-        check(
+        check_no_kw(
             r#"
 struct S(i32, f64);
 fn foo() {
@@ -725,7 +776,7 @@ fn foo() {
 
     #[test]
     fn test_tuple_field_inference() {
-        check(
+        check_no_kw(
             r#"
 pub struct S;
 impl S { pub fn blah(&self) {} }
@@ -747,7 +798,7 @@ impl T {
 
     #[test]
     fn test_field_no_same_name() {
-        check(
+        check_no_kw(
             r#"
 //- minicore: deref
 struct A { field: u8 }
@@ -770,7 +821,7 @@ fn test(a: A) {
 
     #[test]
     fn test_tuple_field_no_same_index() {
-        check(
+        check_no_kw(
             r#"
 //- minicore: deref
 struct A(u8);
@@ -793,7 +844,7 @@ fn test(a: A) {
 
     #[test]
     fn test_tuple_struct_deref_to_tuple_no_same_index() {
-        check(
+        check_no_kw(
             r#"
 //- minicore: deref
 struct A(u8);
@@ -815,7 +866,7 @@ fn test(a: A) {
 
     #[test]
     fn test_completion_works_in_consts() {
-        check(
+        check_no_kw(
             r#"
 struct A { the_field: u32 }
 const X: u32 = {
@@ -830,7 +881,7 @@ const X: u32 = {
 
     #[test]
     fn works_in_simple_macro_1() {
-        check(
+        check_no_kw(
             r#"
 macro_rules! m { ($e:expr) => { $e } }
 struct A { the_field: u32 }
@@ -847,7 +898,7 @@ fn foo(a: A) {
     #[test]
     fn works_in_simple_macro_2() {
         // this doesn't work yet because the macro doesn't expand without the token -- maybe it can be fixed with better recovery
-        check(
+        check_no_kw(
             r#"
 macro_rules! m { ($e:expr) => { $e } }
 struct A { the_field: u32 }
@@ -863,7 +914,7 @@ fn foo(a: A) {
 
     #[test]
     fn works_in_simple_macro_recursive_1() {
-        check(
+        check_no_kw(
             r#"
 macro_rules! m { ($e:expr) => { $e } }
 struct A { the_field: u32 }
@@ -879,7 +930,7 @@ fn foo(a: A) {
 
     #[test]
     fn macro_expansion_resilient() {
-        check(
+        check_no_kw(
             r#"
 macro_rules! d {
     () => {};
@@ -905,7 +956,7 @@ fn foo(a: A) {
 
     #[test]
     fn test_method_completion_issue_3547() {
-        check(
+        check_no_kw(
             r#"
 struct HashSet<T> {}
 impl<T> HashSet<T> {
@@ -924,7 +975,7 @@ fn foo() {
 
     #[test]
     fn completes_method_call_when_receiver_is_a_macro_call() {
-        check(
+        check_no_kw(
             r#"
 struct S;
 impl S { fn foo(&self) {} }
@@ -939,7 +990,7 @@ fn main() { make_s!().f$0; }
 
     #[test]
     fn completes_after_macro_call_in_submodule() {
-        check(
+        check_no_kw(
             r#"
 macro_rules! empty {
     () => {};
@@ -967,7 +1018,7 @@ mod foo {
 
     #[test]
     fn issue_8931() {
-        check(
+        check_no_kw(
             r#"
 //- minicore: fn
 struct S;
@@ -994,7 +1045,7 @@ impl S {
 
     #[test]
     fn completes_bare_fields_and_methods_in_methods() {
-        check(
+        check_no_kw(
             r#"
 struct Foo { field: i32 }
 
@@ -1008,7 +1059,7 @@ impl Foo { fn foo(&self) { $0 } }"#,
                 bt u32              u32
             "#]],
         );
-        check(
+        check_no_kw(
             r#"
 struct Foo(i32);
 
@@ -1026,7 +1077,7 @@ impl Foo { fn foo(&mut self) { $0 } }"#,
 
     #[test]
     fn macro_completion_after_dot() {
-        check(
+        check_no_kw(
             r#"
 macro_rules! m {
     ($e:expr) => { $e };
@@ -1051,7 +1102,7 @@ fn f() {
 
     #[test]
     fn completes_method_call_when_receiver_type_has_errors_issue_10297() {
-        check(
+        check_no_kw(
             r#"
 //- minicore: iterator, sized
 struct Vec<T>;
@@ -1102,7 +1153,7 @@ fn main() {
 
     #[test]
     fn issue_12484() {
-        check(
+        check_no_kw(
             r#"
 //- minicore: sized
 trait SizeUser {
@@ -1124,7 +1175,7 @@ fn test(thing: impl Encrypt) {
 
     #[test]
     fn only_consider_same_type_once() {
-        check(
+        check_no_kw(
             r#"
 //- minicore: deref
 struct A(u8);
@@ -1150,7 +1201,7 @@ fn test(a: A) {
 
     #[test]
     fn no_inference_var_in_completion() {
-        check(
+        check_no_kw(
             r#"
 struct S<T>(T);
 fn test(s: S<Unknown>) {
@@ -1165,7 +1216,7 @@ fn test(s: S<Unknown>) {
 
     #[test]
     fn assoc_impl_1() {
-        check(
+        check_no_kw(
             r#"
 //- minicore: deref
 fn main() {
@@ -1206,7 +1257,7 @@ impl<F: core::ops::Deref<Target = impl Bar>> Foo<F> {
 
     #[test]
     fn assoc_impl_2() {
-        check(
+        check_no_kw(
             r#"
 //- minicore: deref
 fn main() {
@@ -1242,7 +1293,7 @@ impl<B: Bar, F: core::ops::Deref<Target = B>> Foo<F> {
 
     #[test]
     fn test_struct_function_field_completion() {
-        check(
+        check_no_kw(
             r#"
 struct S { va_field: u32, fn_field: fn() }
 fn foo() { S { va_field: 0, fn_field: || {} }.fi$0() }
@@ -1267,7 +1318,7 @@ fn foo() { (S { va_field: 0, fn_field: || {} }.fn_field)() }
 
     #[test]
     fn test_tuple_function_field_completion() {
-        check(
+        check_no_kw(
             r#"
 struct B(u32, fn())
 fn foo() {
@@ -1301,7 +1352,7 @@ fn foo() {
 
     #[test]
     fn test_fn_field_dot_access_method_has_parens_false() {
-        check(
+        check_no_kw(
             r#"
 struct Foo { baz: fn() }
 impl Foo {
@@ -1318,4 +1369,101 @@ fn baz() {
             "#]],
         );
     }
+
+    #[test]
+    fn skip_iter() {
+        check_no_kw(
+            r#"
+        //- minicore: iterator
+        fn foo() {
+            [].$0
+        }
+        "#,
+            expect![[r#"
+                me clone() (as Clone)                                       fn(&self) -> Self
+                me into_iter() (as IntoIterator) fn(self) -> <Self as IntoIterator>::IntoIter
+            "#]],
+        );
+        check_no_kw(
+            r#"
+//- minicore: iterator
+struct MyIntoIter;
+impl IntoIterator for MyIntoIter {
+    type Item = ();
+    type IntoIter = MyIterator;
+    fn into_iter(self) -> Self::IntoIter {
+        MyIterator
+    }
+}
+
+struct MyIterator;
+impl Iterator for MyIterator {
+    type Item = ();
+    fn next(&mut self) -> Self::Item {}
+}
+
+fn foo() {
+    MyIntoIter.$0
+}
+"#,
+            expect![[r#"
+                me into_iter() (as IntoIterator)                fn(self) -> <Self as IntoIterator>::IntoIter
+                me into_iter().by_ref() (as Iterator)                             fn(&mut self) -> &mut Self
+                me into_iter().into_iter() (as IntoIterator)    fn(self) -> <Self as IntoIterator>::IntoIter
+                me into_iter().next() (as Iterator)        fn(&mut self) -> Option<<Self as Iterator>::Item>
+                me into_iter().nth(…) (as Iterator) fn(&mut self, usize) -> Option<<Self as Iterator>::Item>
+            "#]],
+        );
+    }
+
+    #[test]
+    fn skip_await() {
+        check_no_kw(
+            r#"
+//- minicore: future
+struct Foo;
+impl Foo {
+    fn foo(self) {}
+}
+
+async fn foo() -> Foo { Foo }
+
+async fn bar() {
+    foo().$0
+}
+"#,
+            expect![[r#"
+    me await.foo()                                                                      fn(self)
+    me into_future() (use core::future::IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
+"#]],
+        );
+        check_edit(
+            "foo",
+            r#"
+//- minicore: future
+struct Foo;
+impl Foo {
+    fn foo(self) {}
+}
+
+async fn foo() -> Foo { Foo }
+
+async fn bar() {
+    foo().$0
+}
+"#,
+            r#"
+struct Foo;
+impl Foo {
+    fn foo(self) {}
+}
+
+async fn foo() -> Foo { Foo }
+
+async fn bar() {
+    foo().await.foo();$0
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
index 0b6790d42a6..40af5203e9c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
@@ -68,43 +68,40 @@ pub(crate) fn complete_cargo_env_vars(
 mod tests {
     use crate::tests::{check_edit, completion_list};
 
-    fn check(macro_name: &str) {
+    #[test]
+    fn completes_env_variable_in_env() {
         check_edit(
             "CARGO_BIN_NAME",
-            &format!(
-                r#"
-            #[rustc_builtin_macro]
-            macro {macro_name} {{
-                ($var:literal) => {{ 0 }}
-            }}
-
-            fn main() {{
-                let foo = {macro_name}!("CAR$0");
-            }}
-        "#
-            ),
-            &format!(
-                r#"
-            #[rustc_builtin_macro]
-            macro {macro_name} {{
-                ($var:literal) => {{ 0 }}
-            }}
-
-            fn main() {{
-                let foo = {macro_name}!("CARGO_BIN_NAME");
-            }}
-        "#
-            ),
+            r#"
+//- minicore: env
+fn main() {
+    let foo = env!("CAR$0");
+}
+        "#,
+            r#"
+fn main() {
+    let foo = env!("CARGO_BIN_NAME");
+}
+        "#,
         );
     }
-    #[test]
-    fn completes_env_variable_in_env() {
-        check("env")
-    }
 
     #[test]
     fn completes_env_variable_in_option_env() {
-        check("option_env");
+        check_edit(
+            "CARGO_BIN_NAME",
+            r#"
+//- minicore: env
+fn main() {
+    let foo = option_env!("CAR$0");
+}
+        "#,
+            r#"
+fn main() {
+    let foo = option_env!("CARGO_BIN_NAME");
+}
+        "#,
+        );
     }
 
     #[test]
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 c2e5eefe101..db18b531d7c 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
@@ -62,6 +62,7 @@ pub(crate) fn complete_expr_path(
         in_condition,
         incomplete_let,
         ref ref_expr_parent,
+        after_amp,
         ref is_func_update,
         ref innermost_ret_ty,
         ref impl_,
@@ -69,8 +70,23 @@ pub(crate) fn complete_expr_path(
         ..
     } = expr_ctx;
 
-    let wants_mut_token =
-        ref_expr_parent.as_ref().map(|it| it.mut_token().is_none()).unwrap_or(false);
+    let (has_raw_token, has_const_token, has_mut_token) = ref_expr_parent
+        .as_ref()
+        .map(|it| (it.raw_token().is_some(), it.const_token().is_some(), it.mut_token().is_some()))
+        .unwrap_or((false, false, false));
+
+    let wants_raw_token = ref_expr_parent.is_some() && !has_raw_token && after_amp;
+    let wants_const_token =
+        ref_expr_parent.is_some() && has_raw_token && !has_const_token && !has_mut_token;
+    let wants_mut_token = if ref_expr_parent.is_some() {
+        if has_raw_token {
+            !has_const_token && !has_mut_token
+        } else {
+            !has_mut_token
+        }
+    } else {
+        false
+    };
 
     let scope_def_applicable = |def| match def {
         ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) => false,
@@ -354,6 +370,12 @@ pub(crate) fn complete_expr_path(
                         add_keyword("else if", "else if $1 {\n    $0\n}");
                     }
 
+                    if wants_raw_token {
+                        add_keyword("raw", "raw ");
+                    }
+                    if wants_const_token {
+                        add_keyword("const", "const ");
+                    }
                     if wants_mut_token {
                         add_keyword("mut", "mut ");
                     }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs
index bcfda928c4d..7c2cc2a6c1d 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs
@@ -65,18 +65,13 @@ pub(crate) fn complete_extern_abi(
 
 #[cfg(test)]
 mod tests {
-    use expect_test::{expect, Expect};
+    use expect_test::expect;
 
-    use crate::tests::{check_edit, completion_list_no_kw};
-
-    fn check(ra_fixture: &str, expect: Expect) {
-        let actual = completion_list_no_kw(ra_fixture);
-        expect.assert_eq(&actual);
-    }
+    use crate::tests::{check_edit, check_no_kw};
 
     #[test]
     fn only_completes_in_string_literals() {
-        check(
+        check_no_kw(
             r#"
 $0 fn foo {}
 "#,
@@ -86,7 +81,7 @@ $0 fn foo {}
 
     #[test]
     fn requires_extern_prefix() {
-        check(
+        check_no_kw(
             r#"
 "$0" fn foo {}
 "#,
@@ -96,7 +91,7 @@ $0 fn foo {}
 
     #[test]
     fn works() {
-        check(
+        check_no_kw(
             r#"
 extern "$0" fn foo {}
 "#,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
index 3b2b2fd706e..73313eeaa6b 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
@@ -5,7 +5,7 @@ use ide_db::imports::{
     insert_use::ImportScope,
 };
 use itertools::Itertools;
-use syntax::{ast, AstNode, SyntaxNode, ToSmolStr, T};
+use syntax::{ast, AstNode, SyntaxNode, ToSmolStr};
 
 use crate::{
     config::AutoImportExclusionType,
@@ -403,10 +403,11 @@ fn import_on_the_fly_method(
 
 fn import_name(ctx: &CompletionContext<'_>) -> String {
     let token_kind = ctx.token.kind();
-    if matches!(token_kind, T![.] | T![::]) {
-        String::new()
-    } else {
+
+    if token_kind.is_any_identifier() {
         ctx.token.to_string()
+    } else {
+        String::new()
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs
index a87c60c694a..dcd40c3412c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs
@@ -61,18 +61,13 @@ pub(crate) fn format_string(
 
 #[cfg(test)]
 mod tests {
-    use expect_test::{expect, Expect};
+    use expect_test::expect;
 
-    use crate::tests::{check_edit, completion_list_no_kw};
-
-    fn check(ra_fixture: &str, expect: Expect) {
-        let actual = completion_list_no_kw(ra_fixture);
-        expect.assert_eq(&actual);
-    }
+    use crate::tests::{check_edit, check_no_kw};
 
     #[test]
     fn works_when_wrapped() {
-        check(
+        check_no_kw(
             r#"
 //- minicore: fmt
 macro_rules! print {
@@ -89,7 +84,7 @@ fn main() {
 
     #[test]
     fn no_completion_without_brace() {
-        check(
+        check_no_kw(
             r#"
 //- minicore: fmt
 fn main() {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
index 80d72b460f9..6d1945c4534 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
@@ -514,18 +514,13 @@ fn function_declaration(
 
 #[cfg(test)]
 mod tests {
-    use expect_test::{expect, Expect};
+    use expect_test::expect;
 
-    use crate::tests::{check_edit, completion_list_no_kw};
-
-    fn check(ra_fixture: &str, expect: Expect) {
-        let actual = completion_list_no_kw(ra_fixture);
-        expect.assert_eq(&actual)
-    }
+    use crate::tests::{check_edit, check_no_kw};
 
     #[test]
     fn no_completion_inside_fn() {
-        check(
+        check_no_kw(
             r"
 trait Test { fn test(); fn test2(); }
 struct T;
@@ -544,7 +539,7 @@ impl Test for T {
             "#]],
         );
 
-        check(
+        check_no_kw(
             r"
 trait Test { fn test(); fn test2(); }
 struct T;
@@ -558,7 +553,7 @@ impl Test for T {
             expect![[""]],
         );
 
-        check(
+        check_no_kw(
             r"
 trait Test { fn test(); fn test2(); }
 struct T;
@@ -573,7 +568,7 @@ impl Test for T {
         );
 
         // https://github.com/rust-lang/rust-analyzer/pull/5976#issuecomment-692332191
-        check(
+        check_no_kw(
             r"
 trait Test { fn test(); fn test2(); }
 struct T;
@@ -587,7 +582,7 @@ impl Test for T {
             expect![[r#""#]],
         );
 
-        check(
+        check_no_kw(
             r"
 trait Test { fn test(_: i32); fn test2(); }
 struct T;
@@ -606,7 +601,7 @@ impl Test for T {
             "#]],
         );
 
-        check(
+        check_no_kw(
             r"
 trait Test { fn test(_: fn()); fn test2(); }
 struct T;
@@ -624,7 +619,7 @@ impl Test for T {
 
     #[test]
     fn no_completion_inside_const() {
-        check(
+        check_no_kw(
             r"
 trait Test { const TEST: fn(); const TEST2: u32; type Test; fn test(); }
 struct T;
@@ -636,7 +631,7 @@ impl Test for T {
             expect![[r#""#]],
         );
 
-        check(
+        check_no_kw(
             r"
 trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
 struct T;
@@ -653,7 +648,7 @@ impl Test for T {
             "#]],
         );
 
-        check(
+        check_no_kw(
             r"
 trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
 struct T;
@@ -670,7 +665,7 @@ impl Test for T {
             "#]],
         );
 
-        check(
+        check_no_kw(
             r"
 trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
 struct T;
@@ -689,7 +684,7 @@ impl Test for T {
             "#]],
         );
 
-        check(
+        check_no_kw(
             r"
 trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
 struct T;
@@ -703,7 +698,7 @@ impl Test for T {
             expect![[""]],
         );
 
-        check(
+        check_no_kw(
             r"
 trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
 struct T;
@@ -720,7 +715,7 @@ impl Test for T {
 
     #[test]
     fn no_completion_inside_type() {
-        check(
+        check_no_kw(
             r"
 trait Test { type Test; type Test2; fn test(); }
 struct T;
@@ -737,7 +732,7 @@ impl Test for T {
             "#]],
         );
 
-        check(
+        check_no_kw(
             r"
 trait Test { type Test; type Test2; fn test(); }
 struct T;
@@ -1263,7 +1258,7 @@ impl Foo<u32> for Bar {
 
     #[test]
     fn works_directly_in_impl() {
-        check(
+        check_no_kw(
             r#"
 trait Tr {
     fn required();
@@ -1277,7 +1272,7 @@ impl Tr for () {
             fn fn required()
         "#]],
         );
-        check(
+        check_no_kw(
             r#"
 trait Tr {
     fn provided() {}
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 4700ed6c1ae..6541ee502d8 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
@@ -32,14 +32,9 @@ pub(crate) fn complete_for_and_where(
 
 #[cfg(test)]
 mod tests {
-    use expect_test::{expect, Expect};
+    use expect_test::expect;
 
-    use crate::tests::{check_edit, completion_list};
-
-    fn check(ra_fixture: &str, expect: Expect) {
-        let actual = completion_list(ra_fixture);
-        expect.assert_eq(&actual)
-    }
+    use crate::tests::{check, check_edit};
 
     #[test]
     fn test_else_edit_after_if() {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs
index 0692446381b..53a62fe49c5 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs
@@ -59,14 +59,9 @@ pub(crate) fn complete_label(
 
 #[cfg(test)]
 mod tests {
-    use expect_test::{expect, Expect};
+    use expect_test::expect;
 
-    use crate::tests::{check_edit, completion_list};
-
-    fn check(ra_fixture: &str, expect: Expect) {
-        let actual = completion_list(ra_fixture);
-        expect.assert_eq(&actual);
-    }
+    use crate::tests::{check, check_edit};
 
     #[test]
     fn check_lifetime_edit() {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
index f12f011a6bd..bafe3294209 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
@@ -159,14 +159,9 @@ fn module_chain_to_containing_module_file(
 
 #[cfg(test)]
 mod tests {
-    use expect_test::{expect, Expect};
+    use expect_test::expect;
 
-    use crate::tests::completion_list;
-
-    fn check(ra_fixture: &str, expect: Expect) {
-        let actual = completion_list(ra_fixture);
-        expect.assert_eq(&actual);
-    }
+    use crate::tests::check;
 
     #[test]
     fn lib_module_completion() {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
index 7b57eea0524..67ea05e002b 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
@@ -303,7 +303,7 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, ast::Expr) {
 
         resulting_element = ast::Expr::from(parent_deref_element);
 
-        new_element_opt = make::expr_prefix(syntax::T![*], new_element_opt);
+        new_element_opt = make::expr_prefix(syntax::T![*], new_element_opt).into();
     }
 
     if let Some(first_ref_expr) = resulting_element.syntax().parent().and_then(ast::RefExpr::cast) {
@@ -401,18 +401,13 @@ fn add_custom_postfix_completions(
 
 #[cfg(test)]
 mod tests {
-    use expect_test::{expect, Expect};
+    use expect_test::expect;
 
     use crate::{
-        tests::{check_edit, check_edit_with_config, completion_list, TEST_CONFIG},
+        tests::{check, check_edit, check_edit_with_config, TEST_CONFIG},
         CompletionConfig, Snippet,
     };
 
-    fn check(ra_fixture: &str, expect: Expect) {
-        let actual = completion_list(ra_fixture);
-        expect.assert_eq(&actual)
-    }
-
     #[test]
     fn postfix_completion_works_for_trivial_path_expression() {
         check(
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 3705e2c73d6..3a2a4a23a19 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -146,6 +146,7 @@ pub(crate) struct PathExprCtx {
     pub(crate) in_condition: bool,
     pub(crate) incomplete_let: bool,
     pub(crate) ref_expr_parent: Option<ast::RefExpr>,
+    pub(crate) after_amp: bool,
     /// The surrounding RecordExpression we are completing a functional update
     pub(crate) is_func_update: Option<ast::RecordExpr>,
     pub(crate) self_param: Option<hir::SelfParam>,
@@ -390,7 +391,7 @@ pub(crate) struct DotAccess {
     pub(crate) ctx: DotAccessExprCtx,
 }
 
-#[derive(Debug)]
+#[derive(Debug, Clone, Copy)]
 pub(crate) enum DotAccessKind {
     Field {
         /// True if the receiver is an integer and there is no ident in the original file after it yet
@@ -402,7 +403,7 @@ pub(crate) enum DotAccessKind {
     },
 }
 
-#[derive(Debug, PartialEq, Eq)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub(crate) struct DotAccessExprCtx {
     pub(crate) in_block_expr: bool,
     pub(crate) in_breakable: BreakableKind,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
index acce62a041c..3c4d489c0ff 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
@@ -123,10 +123,11 @@ fn expand(
 ) -> Option<ExpansionResult> {
     let _p = tracing::info_span!("CompletionContext::expand").entered();
 
+    // Left biased since there may already be an identifier token there, and we appended to it.
     if !sema.might_be_inside_macro_call(&fake_ident_token)
         && original_file
             .token_at_offset(original_offset + relative_offset)
-            .right_biased()
+            .left_biased()
             .is_some_and(|original_token| !sema.might_be_inside_macro_call(&original_token))
     {
         // Recursion base case.
@@ -1150,6 +1151,9 @@ fn classify_name_ref(
         let after_if_expr = after_if_expr(it.clone());
         let ref_expr_parent =
             path.as_single_name_ref().and_then(|_| it.parent()).and_then(ast::RefExpr::cast);
+        let after_amp = non_trivia_sibling(it.clone().into(), Direction::Prev)
+            .map(|it| it.kind() == SyntaxKind::AMP)
+            .unwrap_or(false);
         let (innermost_ret_ty, self_param) = {
             let find_ret_ty = |it: SyntaxNode| {
                 if let Some(item) = ast::Item::cast(it.clone()) {
@@ -1219,6 +1223,7 @@ fn classify_name_ref(
                 after_if_expr,
                 in_condition,
                 ref_expr_parent,
+                after_amp,
                 is_func_update,
                 innermost_ret_ty,
                 self_param,
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 82a1c10c531..fc2bfc01e62 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
@@ -6,7 +6,7 @@ use crate::{
     tests::{position, TEST_CONFIG},
 };
 
-fn check_expected_type_and_name(ra_fixture: &str, expect: Expect) {
+fn check_expected_type_and_name(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let (db, pos) = position(ra_fixture);
     let config = TEST_CONFIG;
     let (completion_context, _analysis) = CompletionContext::new(&db, pos, &config).unwrap();
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 b91f915619d..dc2f9a76802 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
@@ -79,7 +79,7 @@ pub struct CompletionItem {
     // FIXME: We shouldn't expose Mutability here (that is HIR types at all), its fine for now though
     // until we have more splitting completions in which case we should think about
     // generalizing this. See https://github.com/rust-lang/rust-analyzer/issues/12571
-    pub ref_match: Option<(Mutability, TextSize)>,
+    pub ref_match: Option<(CompletionItemRefMode, TextSize)>,
 
     /// The import data to add to completion's edits.
     /// (ImportPath, LastSegment)
@@ -128,8 +128,15 @@ impl fmt::Debug for CompletionItem {
             s.field("relevance", &self.relevance);
         }
 
-        if let Some((mutability, offset)) = &self.ref_match {
-            s.field("ref_match", &format!("&{}@{offset:?}", mutability.as_keyword_for_ref()));
+        if let Some((ref_mode, offset)) = self.ref_match {
+            let prefix = match ref_mode {
+                CompletionItemRefMode::Reference(mutability) => match mutability {
+                    Mutability::Shared => "&",
+                    Mutability::Mut => "&mut ",
+                },
+                CompletionItemRefMode::Dereference => "*",
+            };
+            s.field("ref_match", &format!("{}@{offset:?}", prefix));
         }
         if self.trigger_call_info {
             s.field("trigger_call_info", &true);
@@ -400,6 +407,12 @@ impl CompletionItemKind {
     }
 }
 
+#[derive(Copy, Clone, Debug)]
+pub enum CompletionItemRefMode {
+    Reference(Mutability),
+    Dereference,
+}
+
 impl CompletionItem {
     pub(crate) fn new(
         kind: impl Into<CompletionItemKind>,
@@ -441,15 +454,14 @@ impl CompletionItem {
         let mut relevance = self.relevance;
         relevance.type_match = Some(CompletionRelevanceTypeMatch::Exact);
 
-        self.ref_match.map(|(mutability, offset)| {
-            (
-                format!("&{}{}", mutability.as_keyword_for_ref(), self.label.primary),
-                ide_db::text_edit::Indel::insert(
-                    offset,
-                    format!("&{}", mutability.as_keyword_for_ref()),
-                ),
-                relevance,
-            )
+        self.ref_match.map(|(mode, offset)| {
+            let prefix = match mode {
+                CompletionItemRefMode::Reference(Mutability::Shared) => "&",
+                CompletionItemRefMode::Reference(Mutability::Mut) => "&mut ",
+                CompletionItemRefMode::Dereference => "*",
+            };
+            let label = format!("{prefix}{}", self.label.primary);
+            (label, ide_db::text_edit::Indel::insert(offset, String::from(prefix)), relevance)
         })
     }
 }
@@ -473,7 +485,7 @@ pub(crate) struct Builder {
     deprecated: bool,
     trigger_call_info: bool,
     relevance: CompletionRelevance,
-    ref_match: Option<(Mutability, TextSize)>,
+    ref_match: Option<(CompletionItemRefMode, TextSize)>,
     edition: Edition,
 }
 
@@ -657,8 +669,12 @@ impl Builder {
         self.imports_to_add.push(import_to_add);
         self
     }
-    pub(crate) fn ref_match(&mut self, mutability: Mutability, offset: TextSize) -> &mut Builder {
-        self.ref_match = Some((mutability, offset));
+    pub(crate) fn ref_match(
+        &mut self,
+        ref_mode: CompletionItemRefMode,
+        offset: TextSize,
+    ) -> &mut Builder {
+        self.ref_match = Some((ref_mode, offset));
         self
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
index ca6c9ad9f08..56d7eeaf8ea 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
@@ -33,8 +33,9 @@ use crate::{
 pub use crate::{
     config::{AutoImportExclusionType, CallableSnippets, CompletionConfig},
     item::{
-        CompletionItem, CompletionItemKind, CompletionRelevance, CompletionRelevancePostfixMatch,
-        CompletionRelevanceReturnType, CompletionRelevanceTypeMatch,
+        CompletionItem, CompletionItemKind, CompletionItemRefMode, CompletionRelevance,
+        CompletionRelevancePostfixMatch, CompletionRelevanceReturnType,
+        CompletionRelevanceTypeMatch,
     },
     snippet::{Snippet, SnippetScope},
 };
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 c239ca512da..61e8114d381 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
@@ -18,7 +18,7 @@ use ide_db::{
     imports::import_assets::LocatedImport,
     RootDatabase, SnippetCap, SymbolKind,
 };
-use syntax::{ast, format_smolstr, AstNode, Edition, SmolStr, SyntaxKind, TextRange, ToSmolStr};
+use syntax::{ast, format_smolstr, AstNode, SmolStr, SyntaxKind, TextRange, ToSmolStr};
 
 use crate::{
     context::{DotAccess, DotAccessKind, PathCompletionCtx, PathKind, PatternContext},
@@ -28,7 +28,8 @@ use crate::{
         literal::render_variant_lit,
         macro_::{render_macro, render_macro_pat},
     },
-    CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
+    CompletionContext, CompletionItem, CompletionItemKind, CompletionItemRefMode,
+    CompletionRelevance,
 };
 /// Interface for data and methods required for items rendering.
 #[derive(Debug, Clone)]
@@ -122,7 +123,7 @@ impl<'a> RenderContext<'a> {
 pub(crate) fn render_field(
     ctx: RenderContext<'_>,
     dot_access: &DotAccess,
-    receiver: Option<hir::Name>,
+    receiver: Option<SmolStr>,
     field: hir::Field,
     ty: &hir::Type,
 ) -> CompletionItem {
@@ -136,7 +137,7 @@ pub(crate) fn render_field(
     let mut item = CompletionItem::new(
         SymbolKind::Field,
         ctx.source_range(),
-        field_with_receiver(db, receiver.as_ref(), &name, ctx.completion.edition),
+        field_with_receiver(receiver.as_deref(), &name),
         ctx.completion.edition,
     );
     item.set_relevance(CompletionRelevance {
@@ -158,8 +159,7 @@ pub(crate) fn render_field(
 
         builder.replace(
             ctx.source_range(),
-            field_with_receiver(db, receiver.as_ref(), &escaped_name, ctx.completion.edition)
-                .into(),
+            field_with_receiver(receiver.as_deref(), &escaped_name).into(),
         );
 
         let expected_fn_type =
@@ -183,17 +183,12 @@ pub(crate) fn render_field(
 
         item.text_edit(builder.finish());
     } else {
-        item.insert_text(field_with_receiver(
-            db,
-            receiver.as_ref(),
-            &escaped_name,
-            ctx.completion.edition,
-        ));
+        item.insert_text(field_with_receiver(receiver.as_deref(), &escaped_name));
     }
     if let Some(receiver) = &dot_access.receiver {
         if let Some(original) = ctx.completion.sema.original_ast_node(receiver.clone()) {
-            if let Some(ref_match) = compute_ref_match(ctx.completion, ty) {
-                item.ref_match(ref_match, original.syntax().text_range().start());
+            if let Some(ref_mode) = compute_ref_match(ctx.completion, ty) {
+                item.ref_match(ref_mode, original.syntax().text_range().start());
             }
         }
     }
@@ -201,33 +196,21 @@ pub(crate) fn render_field(
     item.build(db)
 }
 
-fn field_with_receiver(
-    db: &RootDatabase,
-    receiver: Option<&hir::Name>,
-    field_name: &str,
-    edition: Edition,
-) -> SmolStr {
-    receiver.map_or_else(
-        || field_name.into(),
-        |receiver| format_smolstr!("{}.{field_name}", receiver.display(db, edition)),
-    )
+fn field_with_receiver(receiver: Option<&str>, field_name: &str) -> SmolStr {
+    receiver
+        .map_or_else(|| field_name.into(), |receiver| format_smolstr!("{}.{field_name}", receiver))
 }
 
 pub(crate) fn render_tuple_field(
     ctx: RenderContext<'_>,
-    receiver: Option<hir::Name>,
+    receiver: Option<SmolStr>,
     field: usize,
     ty: &hir::Type,
 ) -> CompletionItem {
     let mut item = CompletionItem::new(
         SymbolKind::Field,
         ctx.source_range(),
-        field_with_receiver(
-            ctx.db(),
-            receiver.as_ref(),
-            &field.to_string(),
-            ctx.completion.edition,
-        ),
+        field_with_receiver(receiver.as_deref(), &field.to_string()),
         ctx.completion.edition,
     );
     item.detail(ty.display(ctx.db(), ctx.completion.edition).to_string())
@@ -440,7 +423,7 @@ fn render_resolution_path(
 
     let name = local_name.display_no_db(ctx.completion.edition).to_smolstr();
     let mut item = render_resolution_simple_(ctx, &local_name, import_to_add, resolution);
-    if local_name.is_escaped(completion.edition) {
+    if local_name.needs_escape(completion.edition) {
         item.insert_text(local_name.display_no_db(completion.edition).to_smolstr());
     }
     // Add `<>` for generic types
@@ -638,20 +621,34 @@ fn compute_exact_name_match(ctx: &CompletionContext<'_>, completion_name: &str)
 fn compute_ref_match(
     ctx: &CompletionContext<'_>,
     completion_ty: &hir::Type,
-) -> Option<hir::Mutability> {
+) -> Option<CompletionItemRefMode> {
     let expected_type = ctx.expected_type.as_ref()?;
-    if completion_ty != expected_type {
-        let expected_type_without_ref = expected_type.remove_ref()?;
-        if completion_ty.autoderef(ctx.db).any(|deref_ty| deref_ty == expected_type_without_ref) {
+    let expected_without_ref = expected_type.remove_ref();
+    let completion_without_ref = completion_ty.remove_ref();
+
+    if completion_ty == expected_type {
+        return None;
+    }
+
+    if let Some(expected_without_ref) = &expected_without_ref {
+        if completion_ty.autoderef(ctx.db).any(|ty| ty == *expected_without_ref) {
             cov_mark::hit!(suggest_ref);
             let mutability = if expected_type.is_mutable_reference() {
                 hir::Mutability::Mut
             } else {
                 hir::Mutability::Shared
             };
-            return Some(mutability);
-        };
+            return Some(CompletionItemRefMode::Reference(mutability));
+        }
+    }
+
+    if let Some(completion_without_ref) = completion_without_ref {
+        if completion_without_ref == *expected_type && completion_without_ref.is_copy(ctx.db) {
+            cov_mark::hit!(suggest_deref);
+            return Some(CompletionItemRefMode::Dereference);
+        }
     }
+
     None
 }
 
@@ -664,16 +661,16 @@ fn path_ref_match(
     if let Some(original_path) = &path_ctx.original_path {
         // At least one char was typed by the user already, in that case look for the original path
         if let Some(original_path) = completion.sema.original_ast_node(original_path.clone()) {
-            if let Some(ref_match) = compute_ref_match(completion, ty) {
-                item.ref_match(ref_match, original_path.syntax().text_range().start());
+            if let Some(ref_mode) = compute_ref_match(completion, ty) {
+                item.ref_match(ref_mode, original_path.syntax().text_range().start());
             }
         }
     } else {
         // completion requested on an empty identifier, there is no path here yet.
         // FIXME: This might create inconsistent completions where we show a ref match in macro inputs
         // as long as nothing was typed yet
-        if let Some(ref_match) = compute_ref_match(completion, ty) {
-            item.ref_match(ref_match, completion.position.offset);
+        if let Some(ref_mode) = compute_ref_match(completion, ty) {
+            item.ref_match(ref_mode, completion.position.offset);
         }
     }
 }
@@ -693,20 +690,28 @@ mod tests {
     };
 
     #[track_caller]
-    fn check(ra_fixture: &str, kind: impl Into<CompletionItemKind>, expect: Expect) {
+    fn check(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        kind: impl Into<CompletionItemKind>,
+        expect: Expect,
+    ) {
         let actual = do_completion(ra_fixture, kind.into());
         expect.assert_debug_eq(&actual);
     }
 
     #[track_caller]
-    fn check_kinds(ra_fixture: &str, kinds: &[CompletionItemKind], expect: Expect) {
+    fn check_kinds(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        kinds: &[CompletionItemKind],
+        expect: Expect,
+    ) {
         let actual: Vec<_> =
             kinds.iter().flat_map(|&kind| do_completion(ra_fixture, kind)).collect();
         expect.assert_debug_eq(&actual);
     }
 
     #[track_caller]
-    fn check_function_relevance(ra_fixture: &str, expect: Expect) {
+    fn check_function_relevance(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
         let actual: Vec<_> =
             do_completion(ra_fixture, CompletionItemKind::SymbolKind(SymbolKind::Method))
                 .into_iter()
@@ -717,7 +722,11 @@ mod tests {
     }
 
     #[track_caller]
-    fn check_relevance_for_kinds(ra_fixture: &str, kinds: &[CompletionItemKind], expect: Expect) {
+    fn check_relevance_for_kinds(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        kinds: &[CompletionItemKind],
+        expect: Expect,
+    ) {
         let mut actual = get_all_items(TEST_CONFIG, ra_fixture, None);
         actual.retain(|it| kinds.contains(&it.kind));
         actual.sort_by_key(|it| cmp::Reverse(it.relevance.score()));
@@ -725,7 +734,7 @@ mod tests {
     }
 
     #[track_caller]
-    fn check_relevance(ra_fixture: &str, expect: Expect) {
+    fn check_relevance(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
         let mut actual = get_all_items(TEST_CONFIG, ra_fixture, None);
         actual.retain(|it| it.kind != CompletionItemKind::Snippet);
         actual.retain(|it| it.kind != CompletionItemKind::Keyword);
@@ -2053,7 +2062,42 @@ fn main() {
     }
 
     #[test]
-    fn suggest_deref() {
+    fn suggest_deref_copy() {
+        cov_mark::check!(suggest_deref);
+        check_relevance(
+            r#"
+//- minicore: copy
+struct Foo;
+
+impl Copy for Foo {}
+impl Clone for Foo {
+    fn clone(&self) -> Self { *self }
+}
+
+fn bar(x: Foo) {}
+
+fn main() {
+    let foo = &Foo;
+    bar($0);
+}
+"#,
+            expect![[r#"
+                st Foo Foo [type]
+                st Foo Foo [type]
+                ex Foo  [type]
+                lc foo &Foo [local]
+                lc *foo [type+local]
+                fn bar(…) fn(Foo) []
+                fn main() fn() []
+                md core  []
+                tt Clone  []
+                tt Copy  []
+            "#]],
+        );
+    }
+
+    #[test]
+    fn suggest_deref_trait() {
         check_relevance(
             r#"
 //- minicore: deref
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 a859d79e243..3b97d67169e 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
@@ -23,7 +23,7 @@ use crate::{
 #[derive(Debug)]
 enum FuncKind<'ctx> {
     Function(&'ctx PathCompletionCtx),
-    Method(&'ctx DotAccess, Option<hir::Name>),
+    Method(&'ctx DotAccess, Option<SmolStr>),
 }
 
 pub(crate) fn render_fn(
@@ -39,7 +39,7 @@ pub(crate) fn render_fn(
 pub(crate) fn render_method(
     ctx: RenderContext<'_>,
     dot_access: &DotAccess,
-    receiver: Option<hir::Name>,
+    receiver: Option<SmolStr>,
     local_name: Option<hir::Name>,
     func: hir::Function,
 ) -> Builder {
@@ -59,16 +59,8 @@ fn render(
 
     let (call, escaped_call) = match &func_kind {
         FuncKind::Method(_, Some(receiver)) => (
-            format_smolstr!(
-                "{}.{}",
-                receiver.unescaped().display(ctx.db()),
-                name.unescaped().display(ctx.db())
-            ),
-            format_smolstr!(
-                "{}.{}",
-                receiver.display(ctx.db(), completion.edition),
-                name.display(ctx.db(), completion.edition)
-            ),
+            format_smolstr!("{}.{}", receiver, name.unescaped().display(ctx.db())),
+            format_smolstr!("{}.{}", receiver, name.display(ctx.db(), completion.edition)),
         ),
         _ => (
             name.unescaped().display(db).to_smolstr(),
@@ -143,8 +135,8 @@ fn render(
         }
         FuncKind::Method(DotAccess { receiver: Some(receiver), .. }, _) => {
             if let Some(original_expr) = completion.sema.original_ast_node(receiver.clone()) {
-                if let Some(ref_match) = compute_ref_match(completion, &ret_type) {
-                    item.ref_match(ref_match, original_expr.syntax().text_range().start());
+                if let Some(ref_mode) = compute_ref_match(completion, &ret_type) {
+                    item.ref_match(ref_mode, original_expr.syntax().text_range().start());
                 }
             }
         }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
index 1815f340532..b7dbf0a6306 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
@@ -89,22 +89,24 @@ pub(crate) const TEST_CONFIG: CompletionConfig<'_> = CompletionConfig {
     exclude_traits: &[],
 };
 
-pub(crate) fn completion_list(ra_fixture: &str) -> String {
+pub(crate) fn completion_list(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String {
     completion_list_with_config(TEST_CONFIG, ra_fixture, true, None)
 }
 
-pub(crate) fn completion_list_no_kw(ra_fixture: &str) -> String {
+pub(crate) fn completion_list_no_kw(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String {
     completion_list_with_config(TEST_CONFIG, ra_fixture, false, None)
 }
 
-pub(crate) fn completion_list_no_kw_with_private_editable(ra_fixture: &str) -> String {
+pub(crate) fn completion_list_no_kw_with_private_editable(
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+) -> String {
     let mut config = TEST_CONFIG;
     config.enable_private_editable = true;
     completion_list_with_config(config, ra_fixture, false, None)
 }
 
 pub(crate) fn completion_list_with_trigger_character(
-    ra_fixture: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
     trigger_character: Option<char>,
 ) -> String {
     completion_list_with_config(TEST_CONFIG, ra_fixture, true, trigger_character)
@@ -112,7 +114,7 @@ pub(crate) fn completion_list_with_trigger_character(
 
 fn completion_list_with_config_raw(
     config: CompletionConfig<'_>,
-    ra_fixture: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
     include_keywords: bool,
     trigger_character: Option<char>,
 ) -> Vec<CompletionItem> {
@@ -135,7 +137,7 @@ fn completion_list_with_config_raw(
 
 fn completion_list_with_config(
     config: CompletionConfig<'_>,
-    ra_fixture: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
     include_keywords: bool,
     trigger_character: Option<char>,
 ) -> String {
@@ -148,7 +150,9 @@ fn completion_list_with_config(
 }
 
 /// Creates analysis from a multi-file fixture, returns positions marked with $0.
-pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
+pub(crate) fn position(
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+) -> (RootDatabase, FilePosition) {
     let change_fixture = ChangeFixture::parse(ra_fixture);
     let mut database = RootDatabase::default();
     database.enable_proc_attr_macros();
@@ -216,7 +220,11 @@ fn render_completion_list(completions: Vec<CompletionItem>) -> String {
 }
 
 #[track_caller]
-pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
+pub(crate) fn check_edit(
+    what: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
+) {
     check_edit_with_config(TEST_CONFIG, what, ra_fixture_before, ra_fixture_after)
 }
 
@@ -253,11 +261,40 @@ pub(crate) fn check_edit_with_config(
     assert_eq_text!(&ra_fixture_after, &actual)
 }
 
-fn check_empty(ra_fixture: &str, expect: Expect) {
+pub(crate) fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let actual = completion_list(ra_fixture);
     expect.assert_eq(&actual);
 }
 
+pub(crate) fn check_with_base_items(
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    expect: Expect,
+) {
+    check(&format!("{BASE_ITEMS_FIXTURE}{ra_fixture}"), expect)
+}
+
+pub(crate) fn check_no_kw(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
+    let actual = completion_list_no_kw(ra_fixture);
+    expect.assert_eq(&actual)
+}
+
+pub(crate) fn check_with_private_editable(
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    expect: Expect,
+) {
+    let actual = completion_list_no_kw_with_private_editable(ra_fixture);
+    expect.assert_eq(&actual);
+}
+
+pub(crate) fn check_with_trigger_character(
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    trigger_character: Option<char>,
+    expect: Expect,
+) {
+    let actual = completion_list_with_trigger_character(ra_fixture, trigger_character);
+    expect.assert_eq(&actual)
+}
+
 pub(crate) fn get_all_items(
     config: CompletionConfig<'_>,
     code: &str,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs
index ebf35820570..32d3b50f237 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs
@@ -1,12 +1,7 @@
 //! Completion tests for attributes.
-use expect_test::{expect, Expect};
+use expect_test::expect;
 
-use crate::tests::{check_edit, completion_list};
-
-fn check(ra_fixture: &str, expect: Expect) {
-    let actual = completion_list(ra_fixture);
-    expect.assert_eq(&actual);
-}
+use crate::tests::{check, check_edit};
 
 #[test]
 fn derive_helpers() {
@@ -788,14 +783,9 @@ mod cfg {
 mod derive {
     use super::*;
 
-    fn check_derive(ra_fixture: &str, expect: Expect) {
-        let actual = completion_list(ra_fixture);
-        expect.assert_eq(&actual);
-    }
-
     #[test]
     fn no_completion_for_incorrect_derive() {
-        check_derive(
+        check(
             r#"
 //- minicore: derive, copy, clone, ord, eq, default, fmt
 #[derive{$0)] struct Test;
@@ -806,7 +796,7 @@ mod derive {
 
     #[test]
     fn empty_derive() {
-        check_derive(
+        check(
             r#"
 //- minicore: derive, copy, clone, ord, eq, default, fmt
 #[derive($0)] struct Test;
@@ -828,7 +818,7 @@ mod derive {
 
     #[test]
     fn derive_with_input_before() {
-        check_derive(
+        check(
             r#"
 //- minicore: derive, copy, clone, ord, eq, default, fmt
 #[derive(serde::Serialize, PartialEq, $0)] struct Test;
@@ -849,7 +839,7 @@ mod derive {
 
     #[test]
     fn derive_with_input_after() {
-        check_derive(
+        check(
             r#"
 //- minicore: derive, copy, clone, ord, eq, default, fmt
 #[derive($0 serde::Serialize, PartialEq)] struct Test;
@@ -870,7 +860,7 @@ mod derive {
 
     #[test]
     fn derive_with_existing_derives() {
-        check_derive(
+        check(
             r#"
 //- minicore: derive, copy, clone, ord, eq, default, fmt
 #[derive(PartialEq, Eq, Or$0)] struct Test;
@@ -890,7 +880,7 @@ mod derive {
 
     #[test]
     fn derive_flyimport() {
-        check_derive(
+        check(
             r#"
 //- proc_macros: derive_identity
 //- minicore: derive
@@ -904,7 +894,7 @@ mod derive {
                 kw self::
             "#]],
         );
-        check_derive(
+        check(
             r#"
 //- proc_macros: derive_identity
 //- minicore: derive
@@ -940,7 +930,7 @@ use proc_macros::DeriveIdentity;
 
     #[test]
     fn qualified() {
-        check_derive(
+        check(
             r#"
 //- proc_macros: derive_identity
 //- minicore: derive, copy, clone
@@ -950,7 +940,7 @@ use proc_macros::DeriveIdentity;
                 de DeriveIdentity proc_macro DeriveIdentity
             "#]],
         );
-        check_derive(
+        check(
             r#"
 //- proc_macros: derive_identity
 //- minicore: derive, copy, clone
@@ -1056,19 +1046,14 @@ mod lint {
 mod repr {
     use super::*;
 
-    fn check_repr(ra_fixture: &str, expect: Expect) {
-        let actual = completion_list(ra_fixture);
-        expect.assert_eq(&actual);
-    }
-
     #[test]
     fn no_completion_for_incorrect_repr() {
-        check_repr(r#"#[repr{$0)] struct Test;"#, expect![[]])
+        check(r#"#[repr{$0)] struct Test;"#, expect![[]])
     }
 
     #[test]
     fn empty() {
-        check_repr(
+        check(
             r#"#[repr($0)] struct Test;"#,
             expect![[r#"
                 ba C
@@ -1093,12 +1078,12 @@ mod repr {
 
     #[test]
     fn transparent() {
-        check_repr(r#"#[repr(transparent, $0)] struct Test;"#, expect![[r#""#]]);
+        check(r#"#[repr(transparent, $0)] struct Test;"#, expect![[r#""#]]);
     }
 
     #[test]
     fn align() {
-        check_repr(
+        check(
             r#"#[repr(align(1), $0)] struct Test;"#,
             expect![[r#"
                 ba C
@@ -1121,7 +1106,7 @@ mod repr {
 
     #[test]
     fn packed() {
-        check_repr(
+        check(
             r#"#[repr(packed, $0)] struct Test;"#,
             expect![[r#"
                 ba C
@@ -1144,7 +1129,7 @@ mod repr {
 
     #[test]
     fn c() {
-        check_repr(
+        check(
             r#"#[repr(C, $0)] struct Test;"#,
             expect![[r#"
                 ba align($0)
@@ -1167,7 +1152,7 @@ mod repr {
 
     #[test]
     fn prim() {
-        check_repr(
+        check(
             r#"#[repr(usize, $0)] struct Test;"#,
             expect![[r#"
                 ba C
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 30466148686..e117dbf4bdf 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
@@ -4,18 +4,17 @@ use expect_test::{expect, Expect};
 use crate::{
     config::AutoImportExclusionType,
     tests::{
-        check_edit, check_empty, completion_list, completion_list_with_config, BASE_ITEMS_FIXTURE,
+        check, check_edit, check_with_base_items, completion_list_with_config, BASE_ITEMS_FIXTURE,
         TEST_CONFIG,
     },
     CompletionConfig,
 };
 
-fn check(ra_fixture: &str, expect: Expect) {
-    let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}{ra_fixture}"));
-    expect.assert_eq(&actual)
-}
-
-fn check_with_config(config: CompletionConfig<'_>, ra_fixture: &str, expect: Expect) {
+fn check_with_config(
+    config: CompletionConfig<'_>,
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    expect: Expect,
+) {
     let actual = completion_list_with_config(
         config,
         &format!("{BASE_ITEMS_FIXTURE}{ra_fixture}"),
@@ -28,7 +27,7 @@ fn check_with_config(config: CompletionConfig<'_>, ra_fixture: &str, expect: Exp
 #[test]
 fn complete_literal_struct_with_a_private_field() {
     // `FooDesc.bar` is private, the completion should not be triggered.
-    check(
+    check_with_base_items(
         r#"
 mod _69latrick {
     pub struct FooDesc { pub six: bool, pub neuf: Vec<String>, bar: bool }
@@ -67,6 +66,7 @@ fn baz() {
             kw loop
             kw match
             kw mut
+            kw raw
             kw return
             kw self::
             kw true
@@ -79,7 +79,7 @@ fn baz() {
 
 #[test]
 fn completes_various_bindings() {
-    check_empty(
+    check(
         r#"
 fn func(param0 @ (param1, param2): (i32, i32)) {
     let letlocal = 92;
@@ -125,7 +125,7 @@ fn func(param0 @ (param1, param2): (i32, i32)) {
 
 #[test]
 fn completes_all_the_things_in_fn_body() {
-    check(
+    check_with_base_items(
         r#"
 use non_existent::Unresolved;
 mod qualified { pub enum Enum { Variant } }
@@ -191,7 +191,7 @@ impl Unit {
             ?? Unresolved
         "#]],
     );
-    check(
+    check_with_base_items(
         r#"
 use non_existent::Unresolved;
 mod qualified { pub enum Enum { Variant } }
@@ -224,7 +224,7 @@ impl Unit {
 
 #[test]
 fn complete_in_block() {
-    check_empty(
+    check(
         r#"
     fn foo() {
         if true {
@@ -273,7 +273,7 @@ fn complete_in_block() {
 
 #[test]
 fn complete_after_if_expr() {
-    check_empty(
+    check(
         r#"
     fn foo() {
         if true {}
@@ -321,7 +321,7 @@ fn complete_after_if_expr() {
 
 #[test]
 fn complete_in_match_arm() {
-    check_empty(
+    check(
         r#"
     fn foo() {
         match () {
@@ -351,7 +351,7 @@ fn complete_in_match_arm() {
 
 #[test]
 fn completes_in_loop_ctx() {
-    check_empty(
+    check(
         r"fn my() { loop { $0 } }",
         expect![[r#"
             fn my()   fn()
@@ -390,7 +390,7 @@ fn completes_in_loop_ctx() {
             sn ppd
         "#]],
     );
-    check_empty(
+    check(
         r"fn my() { loop { foo.$0 } }",
         expect![[r#"
             sn box  Box::new(expr)
@@ -415,7 +415,7 @@ fn completes_in_loop_ctx() {
 
 #[test]
 fn completes_in_let_initializer() {
-    check_empty(
+    check(
         r#"fn main() { let _ = $0 }"#,
         expect![[r#"
             fn main() fn()
@@ -438,8 +438,116 @@ fn completes_in_let_initializer() {
 }
 
 #[test]
+fn completes_after_ref_expr() {
+    check(
+        r#"fn main() { let _ = &$0 }"#,
+        expect![[r#"
+            fn main() fn()
+            bt u32     u32
+            kw crate::
+            kw false
+            kw for
+            kw if
+            kw if let
+            kw loop
+            kw match
+            kw mut
+            kw raw
+            kw return
+            kw self::
+            kw true
+            kw unsafe
+            kw while
+            kw while let
+        "#]],
+    );
+    check(
+        r#"fn main() { let _ = &raw $0 }"#,
+        expect![[r#"
+            fn main() fn()
+            bt u32     u32
+            kw const
+            kw crate::
+            kw false
+            kw for
+            kw if
+            kw if let
+            kw loop
+            kw match
+            kw mut
+            kw return
+            kw self::
+            kw true
+            kw unsafe
+            kw while
+            kw while let
+        "#]],
+    );
+    check(
+        r#"fn main() { let _ = &raw const $0 }"#,
+        expect![[r#"
+            fn main() fn()
+            bt u32     u32
+            kw crate::
+            kw false
+            kw for
+            kw if
+            kw if let
+            kw loop
+            kw match
+            kw return
+            kw self::
+            kw true
+            kw unsafe
+            kw while
+            kw while let
+        "#]],
+    );
+    check(
+        r#"fn main() { let _ = &raw mut $0 }"#,
+        expect![[r#"
+            fn main() fn()
+            bt u32     u32
+            kw crate::
+            kw false
+            kw for
+            kw if
+            kw if let
+            kw loop
+            kw match
+            kw return
+            kw self::
+            kw true
+            kw unsafe
+            kw while
+            kw while let
+        "#]],
+    );
+    check(
+        r#"fn main() { let _ = &mut $0 }"#,
+        expect![[r#"
+            fn main() fn()
+            bt u32     u32
+            kw crate::
+            kw false
+            kw for
+            kw if
+            kw if let
+            kw loop
+            kw match
+            kw return
+            kw self::
+            kw true
+            kw unsafe
+            kw while
+            kw while let
+        "#]],
+    )
+}
+
+#[test]
 fn struct_initializer_field_expr() {
-    check_empty(
+    check(
         r#"
 struct Foo {
     pub f: i32,
@@ -475,7 +583,7 @@ fn foo() {
 fn shadowing_shows_single_completion() {
     cov_mark::check!(shadowing_shows_single_completion);
 
-    check_empty(
+    check(
         r#"
 fn foo() {
     let bar = 92;
@@ -508,7 +616,7 @@ fn foo() {
 
 #[test]
 fn in_macro_expr_frag() {
-    check_empty(
+    check(
         r#"
 macro_rules! m { ($e:expr) => { $e } }
 fn quux(x: i32) {
@@ -535,7 +643,7 @@ fn quux(x: i32) {
             kw while let
         "#]],
     );
-    check_empty(
+    check(
         r"
 macro_rules! m { ($e:expr) => { $e } }
 fn quux(x: i32) {
@@ -562,7 +670,7 @@ fn quux(x: i32) {
             kw while let
         "#]],
     );
-    check_empty(
+    check(
         r#"
 macro_rules! m { ($e:expr) => { $e } }
 fn quux(x: i32) {
@@ -595,7 +703,7 @@ fn quux(x: i32) {
 
 #[test]
 fn enum_qualified() {
-    check(
+    check_with_base_items(
         r#"
 impl Enum {
     type AssocType = ();
@@ -619,7 +727,7 @@ fn func() {
 
 #[test]
 fn ty_qualified_no_drop() {
-    check_empty(
+    check(
         r#"
 //- minicore: drop
 struct Foo;
@@ -636,7 +744,7 @@ fn func() {
 
 #[test]
 fn with_parens() {
-    check_empty(
+    check(
         r#"
 enum Enum {
     Variant()
@@ -657,7 +765,7 @@ fn func() {
 
 #[test]
 fn detail_impl_trait_in_return_position() {
-    check_empty(
+    check(
         r"
 //- minicore: sized
 trait Trait<T> {}
@@ -676,7 +784,7 @@ fn main() {
 
 #[test]
 fn detail_async_fn() {
-    check_empty(
+    check(
         r#"
 //- minicore: future, sized
 trait Trait<T> {}
@@ -697,7 +805,7 @@ fn main() {
 
 #[test]
 fn detail_impl_trait_in_argument_position() {
-    check_empty(
+    check(
         r"
 //- minicore: sized
 trait Trait<T> {}
@@ -717,7 +825,7 @@ fn main() {
 
 #[test]
 fn complete_record_expr_path() {
-    check(
+    check_with_base_items(
         r#"
 struct Zulu;
 impl Zulu {
@@ -738,7 +846,7 @@ fn main() {
 
 #[test]
 fn variant_with_struct() {
-    check_empty(
+    check(
         r#"
 pub struct YoloVariant {
     pub f: usize
@@ -813,7 +921,7 @@ fn return_value_no_block() {
 
 #[test]
 fn else_completion_after_if() {
-    check_empty(
+    check(
         r#"
 fn foo() { if foo {} $0 }
 "#,
@@ -854,7 +962,7 @@ fn foo() { if foo {} $0 }
             sn ppd
         "#]],
     );
-    check_empty(
+    check(
         r#"
 fn foo() { if foo {} el$0 }
 "#,
@@ -895,7 +1003,7 @@ fn foo() { if foo {} el$0 }
             sn ppd
         "#]],
     );
-    check_empty(
+    check(
         r#"
 fn foo() { bar(if foo {} $0) }
 "#,
@@ -919,7 +1027,7 @@ fn foo() { bar(if foo {} $0) }
             kw while let
         "#]],
     );
-    check_empty(
+    check(
         r#"
 fn foo() { bar(if foo {} el$0) }
 "#,
@@ -943,7 +1051,7 @@ fn foo() { bar(if foo {} el$0) }
             kw while let
         "#]],
     );
-    check_empty(
+    check(
         r#"
 fn foo() { if foo {} $0 let x = 92; }
 "#,
@@ -984,7 +1092,7 @@ fn foo() { if foo {} $0 let x = 92; }
             sn ppd
         "#]],
     );
-    check_empty(
+    check(
         r#"
 fn foo() { if foo {} el$0 let x = 92; }
 "#,
@@ -1025,7 +1133,7 @@ fn foo() { if foo {} el$0 let x = 92; }
             sn ppd
         "#]],
     );
-    check_empty(
+    check(
         r#"
 fn foo() { if foo {} el$0 { let x = 92; } }
 "#,
@@ -1070,7 +1178,7 @@ fn foo() { if foo {} el$0 { let x = 92; } }
 
 #[test]
 fn expr_no_unstable_item_on_stable() {
-    check_empty(
+    check(
         r#"
 //- /main.rs crate:main deps:std
 use std::*;
@@ -1121,7 +1229,7 @@ pub struct UnstableThisShouldNotBeListed;
 
 #[test]
 fn expr_unstable_item_on_nightly() {
-    check_empty(
+    check(
         r#"
 //- toolchain:nightly
 //- /main.rs crate:main deps:std
@@ -1174,7 +1282,7 @@ pub struct UnstableButWeAreOnNightlyAnyway;
 
 #[test]
 fn inside_format_args_completions_work() {
-    check_empty(
+    check(
         r#"
 //- minicore: fmt
 struct Foo;
@@ -1200,7 +1308,7 @@ fn main() {
             sn unsafe    unsafe {}
         "#]],
     );
-    check_empty(
+    check(
         r#"
 //- minicore: fmt
 struct Foo;
@@ -1230,7 +1338,7 @@ fn main() {
 
 #[test]
 fn inside_faulty_format_args_completions_work() {
-    check_empty(
+    check(
         r#"
 //- minicore: fmt
 struct Foo;
@@ -1256,7 +1364,7 @@ fn main() {
             sn unsafe    unsafe {}
         "#]],
     );
-    check_empty(
+    check(
         r#"
 //- minicore: fmt
 struct Foo;
@@ -1282,7 +1390,7 @@ fn main() {
             sn unsafe    unsafe {}
         "#]],
     );
-    check_empty(
+    check(
         r#"
 //- minicore: fmt
 struct Foo;
@@ -1308,7 +1416,7 @@ fn main() {
             sn unsafe    unsafe {}
         "#]],
     );
-    check_empty(
+    check(
         r#"
 //- minicore: fmt
 struct Foo;
@@ -1340,7 +1448,7 @@ fn main() {
 
 #[test]
 fn macro_that_ignores_completion_marker() {
-    check(
+    check_with_base_items(
         r#"
 macro_rules! helper {
     ($v:ident) => {};
@@ -1788,7 +1896,7 @@ fn foo<T: ExcludedTrait>() {
 
 #[test]
 fn hide_ragennew_synthetic_identifiers() {
-    check_empty(
+    check(
         r#"
 //- minicore: iterator
 fn bar() {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs
index d413977f7c8..d491e438fef 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs
@@ -6,11 +6,15 @@ use crate::{
     CompletionConfig,
 };
 
-fn check(ra_fixture: &str, expect: Expect) {
+fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     check_with_config(TEST_CONFIG, ra_fixture, expect);
 }
 
-fn check_with_config(config: CompletionConfig<'_>, ra_fixture: &str, expect: Expect) {
+fn check_with_config(
+    config: CompletionConfig<'_>,
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    expect: Expect,
+) {
     let (db, position) = crate::tests::position(ra_fixture);
     let (ctx, analysis) = crate::context::CompletionContext::new(&db, position, &config).unwrap();
 
@@ -1742,7 +1746,7 @@ fn intrinsics() {
     fn function() {
             transmute$0
     }
-    "#,
+"#,
         expect![[r#"
             fn transmute(…) (use core::mem::transmute) unsafe fn(Src) -> Dst
         "#]],
@@ -1763,7 +1767,9 @@ fn function() {
         mem::transmute$0
 }
 "#,
-        expect![""],
+        expect![[r#"
+            fn transmute(…) (use core::mem) unsafe fn(Src) -> Dst
+        "#]],
     );
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs
index 4a89f874e15..451ce07c745 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs
@@ -1,16 +1,6 @@
-use expect_test::{expect, Expect};
+use expect_test::expect;
 
-use crate::tests::{completion_list, completion_list_with_trigger_character};
-
-fn check(ra_fixture: &str, expect: Expect) {
-    let actual = completion_list(ra_fixture);
-    expect.assert_eq(&actual);
-}
-
-fn check_with_trigger_character(ra_fixture: &str, trigger_character: char, expect: Expect) {
-    let actual = completion_list_with_trigger_character(ra_fixture, Some(trigger_character));
-    expect.assert_eq(&actual)
-}
+use crate::tests::{check, check_with_trigger_character};
 
 #[test]
 fn only_param() {
@@ -124,7 +114,7 @@ fn trigger_by_l_paren() {
         r#"
 fn foo($0)
 "#,
-        '(',
+        Some('('),
         expect![[]],
     )
 }
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 79561a0419f..bea6d60769c 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
@@ -2,20 +2,13 @@
 //!
 //! Except for use items which are tested in [super::use_tree] and mod declarations with are tested
 //! in [crate::completions::mod_].
-use expect_test::{expect, Expect};
+use expect_test::expect;
 
-use crate::tests::{completion_list, BASE_ITEMS_FIXTURE};
-
-use super::check_edit;
-
-fn check(ra_fixture: &str, expect: Expect) {
-    let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}{ra_fixture}"));
-    expect.assert_eq(&actual)
-}
+use crate::tests::{check_edit, check_with_base_items};
 
 #[test]
 fn target_type_or_trait_in_impl_block() {
-    check(
+    check_with_base_items(
         r#"
 impl Tra$0
 "#,
@@ -37,7 +30,7 @@ impl Tra$0
 
 #[test]
 fn target_type_in_trait_impl_block() {
-    check(
+    check_with_base_items(
         r#"
 impl Trait for Str$0
 "#,
@@ -59,7 +52,7 @@ impl Trait for Str$0
 
 #[test]
 fn after_trait_name_in_trait_def() {
-    check(
+    check_with_base_items(
         r"trait A $0",
         expect![[r#"
             kw where
@@ -69,21 +62,21 @@ fn after_trait_name_in_trait_def() {
 
 #[test]
 fn after_target_name_in_impl() {
-    check(
+    check_with_base_items(
         r"impl Trait $0",
         expect![[r#"
             kw for
             kw where
         "#]],
     );
-    check(
+    check_with_base_items(
         r"impl Trait f$0",
         expect![[r#"
             kw for
             kw where
         "#]],
     );
-    check(
+    check_with_base_items(
         r"impl Trait for Type $0",
         expect![[r#"
             kw where
@@ -93,44 +86,44 @@ fn after_target_name_in_impl() {
 
 #[test]
 fn completes_where() {
-    check(
+    check_with_base_items(
         r"struct Struct $0",
         expect![[r#"
         kw where
     "#]],
     );
-    check(
+    check_with_base_items(
         r"struct Struct $0 {}",
         expect![[r#"
         kw where
     "#]],
     );
     // FIXME: This shouldn't be completed here
-    check(
+    check_with_base_items(
         r"struct Struct $0 ()",
         expect![[r#"
         kw where
     "#]],
     );
-    check(
+    check_with_base_items(
         r"fn func() $0",
         expect![[r#"
         kw where
     "#]],
     );
-    check(
+    check_with_base_items(
         r"enum Enum $0",
         expect![[r#"
         kw where
     "#]],
     );
-    check(
+    check_with_base_items(
         r"enum Enum $0 {}",
         expect![[r#"
         kw where
     "#]],
     );
-    check(
+    check_with_base_items(
         r"trait Trait $0 {}",
         expect![[r#"
         kw where
@@ -140,7 +133,7 @@ fn completes_where() {
 
 #[test]
 fn before_record_field() {
-    check(
+    check_with_base_items(
         r#"
 struct Foo {
     $0
@@ -244,7 +237,7 @@ impl Copy for S where $0
 
 #[test]
 fn test_is_not_considered_macro() {
-    check(
+    check_with_base_items(
         r#"
 #[rustc_builtin]
 pub macro test($item:item) {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs
index d3d52dc6dfc..841c42123a0 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs
@@ -1,16 +1,11 @@
 //! Completion tests for item list position.
-use expect_test::{expect, Expect};
+use expect_test::expect;
 
-use crate::tests::{check_edit, check_empty, completion_list, BASE_ITEMS_FIXTURE};
-
-fn check(ra_fixture: &str, expect: Expect) {
-    let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}{ra_fixture}"));
-    expect.assert_eq(&actual)
-}
+use crate::tests::{check, check_edit, check_with_base_items};
 
 #[test]
 fn in_mod_item_list() {
-    check(
+    check_with_base_items(
         r#"mod tests { $0 }"#,
         expect![[r#"
             ma makro!(…) macro_rules! makro
@@ -43,7 +38,7 @@ fn in_mod_item_list() {
 
 #[test]
 fn in_source_file_item_list() {
-    check(
+    check_with_base_items(
         r#"$0"#,
         expect![[r#"
             ma makro!(…) macro_rules! makro
@@ -76,7 +71,7 @@ fn in_source_file_item_list() {
 
 #[test]
 fn in_item_list_after_attr() {
-    check(
+    check_with_base_items(
         r#"#[attr] $0"#,
         expect![[r#"
             ma makro!(…) macro_rules! makro
@@ -109,7 +104,7 @@ fn in_item_list_after_attr() {
 
 #[test]
 fn in_qualified_path() {
-    check(
+    check_with_base_items(
         r#"crate::$0"#,
         expect![[r#"
             ma makro!(…) macro_rules! makro
@@ -120,7 +115,7 @@ fn in_qualified_path() {
 
 #[test]
 fn after_unsafe_token() {
-    check(
+    check_with_base_items(
         r#"unsafe $0"#,
         expect![[r#"
             kw async
@@ -134,7 +129,7 @@ fn after_unsafe_token() {
 
 #[test]
 fn after_async_token() {
-    check(
+    check_with_base_items(
         r#"async $0"#,
         expect![[r#"
             kw fn
@@ -145,7 +140,7 @@ fn after_async_token() {
 
 #[test]
 fn after_visibility() {
-    check(
+    check_with_base_items(
         r#"pub $0"#,
         expect![[r#"
             kw async
@@ -167,7 +162,7 @@ fn after_visibility() {
 
 #[test]
 fn after_visibility_unsafe() {
-    check(
+    check_with_base_items(
         r#"pub unsafe $0"#,
         expect![[r#"
             kw async
@@ -179,7 +174,7 @@ fn after_visibility_unsafe() {
 
 #[test]
 fn in_impl_assoc_item_list() {
-    check(
+    check_with_base_items(
         r#"impl Struct { $0 }"#,
         expect![[r#"
             ma makro!(…) macro_rules! makro
@@ -199,7 +194,7 @@ fn in_impl_assoc_item_list() {
 
 #[test]
 fn in_impl_assoc_item_list_after_attr() {
-    check(
+    check_with_base_items(
         r#"impl Struct { #[attr] $0 }"#,
         expect![[r#"
             ma makro!(…) macro_rules! makro
@@ -219,7 +214,7 @@ fn in_impl_assoc_item_list_after_attr() {
 
 #[test]
 fn in_trait_assoc_item_list() {
-    check(
+    check_with_base_items(
         r"trait Foo { $0 }",
         expect![[r#"
             ma makro!(…) macro_rules! makro
@@ -237,7 +232,7 @@ fn in_trait_assoc_item_list() {
 
 #[test]
 fn in_trait_assoc_fn_missing_body() {
-    check(
+    check_with_base_items(
         r#"trait Foo { fn function(); $0 }"#,
         expect![[r#"
             ma makro!(…) macro_rules! makro
@@ -255,7 +250,7 @@ fn in_trait_assoc_fn_missing_body() {
 
 #[test]
 fn in_trait_assoc_const_missing_body() {
-    check(
+    check_with_base_items(
         r#"trait Foo { const CONST: (); $0 }"#,
         expect![[r#"
             ma makro!(…) macro_rules! makro
@@ -273,7 +268,7 @@ fn in_trait_assoc_const_missing_body() {
 
 #[test]
 fn in_trait_assoc_type_aliases_missing_ty() {
-    check(
+    check_with_base_items(
         r#"trait Foo { type Type; $0 }"#,
         expect![[r#"
             ma makro!(…) macro_rules! makro
@@ -291,7 +286,7 @@ fn in_trait_assoc_type_aliases_missing_ty() {
 
 #[test]
 fn in_trait_impl_assoc_item_list() {
-    check(
+    check_with_base_items(
         r#"
 trait Test {
     type Type0;
@@ -326,7 +321,7 @@ impl Test for () {
 
 #[test]
 fn in_trait_impl_no_unstable_item_on_stable() {
-    check_empty(
+    check(
         r#"
 trait Test {
     #[unstable]
@@ -350,7 +345,7 @@ impl Test for () {
 
 #[test]
 fn in_trait_impl_unstable_item_on_nightly() {
-    check_empty(
+    check(
         r#"
 //- toolchain:nightly
 trait Test {
@@ -378,7 +373,7 @@ impl Test for () {
 
 #[test]
 fn after_unit_struct() {
-    check(
+    check_with_base_items(
         r#"struct S; f$0"#,
         expect![[r#"
             ma makro!(…) macro_rules! makro
@@ -500,7 +495,7 @@ type O = $0;
 #[test]
 fn inside_extern_blocks() {
     // Should suggest `fn`, `static`, `unsafe`
-    check(
+    check_with_base_items(
         r#"extern { $0 }"#,
         expect![[r#"
             ma makro!(…) macro_rules! makro
@@ -517,7 +512,7 @@ fn inside_extern_blocks() {
     );
 
     // Should suggest `fn`, `static`, `safe`, `unsafe`
-    check(
+    check_with_base_items(
         r#"unsafe extern { $0 }"#,
         expect![[r#"
             ma makro!(…) macro_rules! makro
@@ -534,7 +529,7 @@ fn inside_extern_blocks() {
         "#]],
     );
 
-    check(
+    check_with_base_items(
         r#"unsafe extern { pub safe $0 }"#,
         expect![[r#"
             kw fn
@@ -542,7 +537,7 @@ fn inside_extern_blocks() {
         "#]],
     );
 
-    check(
+    check_with_base_items(
         r#"unsafe extern { pub unsafe $0 }"#,
         expect![[r#"
             kw fn
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs
index 2f1f555e524..9ec27252fd7 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs
@@ -1,16 +1,11 @@
 //! Completion tests for pattern position.
-use expect_test::{expect, Expect};
+use expect_test::expect;
 
-use crate::tests::{check_edit, check_empty, completion_list, BASE_ITEMS_FIXTURE};
-
-fn check(ra_fixture: &str, expect: Expect) {
-    let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}\n{ra_fixture}"));
-    expect.assert_eq(&actual)
-}
+use crate::tests::{check, check_edit, check_with_base_items};
 
 #[test]
 fn wildcard() {
-    check(
+    check_with_base_items(
         r#"
 fn quux() {
     let _$0
@@ -22,7 +17,7 @@ fn quux() {
 
 #[test]
 fn ident_rebind_pat() {
-    check_empty(
+    check(
         r#"
 fn quux() {
     let en$0 @ x
@@ -37,7 +32,7 @@ fn quux() {
 
 #[test]
 fn ident_ref_pat() {
-    check_empty(
+    check(
         r#"
 fn quux() {
     let ref en$0
@@ -47,7 +42,7 @@ fn quux() {
             kw mut
         "#]],
     );
-    check_empty(
+    check(
         r#"
 fn quux() {
     let ref en$0 @ x
@@ -61,7 +56,7 @@ fn quux() {
 
 #[test]
 fn ident_ref_mut_pat() {
-    check_empty(
+    check(
         r#"
 fn quux() {
     let ref mut en$0
@@ -69,7 +64,7 @@ fn quux() {
 "#,
         expect![[r#""#]],
     );
-    check_empty(
+    check(
         r#"
 fn quux() {
     let ref mut en$0 @ x
@@ -81,7 +76,7 @@ fn quux() {
 
 #[test]
 fn ref_pat() {
-    check_empty(
+    check(
         r#"
 fn quux() {
     let &en$0
@@ -91,7 +86,7 @@ fn quux() {
             kw mut
         "#]],
     );
-    check_empty(
+    check(
         r#"
 fn quux() {
     let &mut en$0
@@ -99,7 +94,7 @@ fn quux() {
 "#,
         expect![[r#""#]],
     );
-    check_empty(
+    check(
         r#"
 fn foo() {
     for &$0 in () {}
@@ -113,7 +108,7 @@ fn foo() {
 
 #[test]
 fn refutable() {
-    check(
+    check_with_base_items(
         r#"
 fn foo() {
     if let a$0
@@ -139,7 +134,7 @@ fn foo() {
 
 #[test]
 fn irrefutable() {
-    check(
+    check_with_base_items(
         r#"
 enum SingleVariantEnum {
     Variant
@@ -168,7 +163,7 @@ fn foo() {
 
 #[test]
 fn in_param() {
-    check(
+    check_with_base_items(
         r#"
 fn foo(a$0) {
 }
@@ -185,7 +180,7 @@ fn foo(a$0) {
             kw ref
         "#]],
     );
-    check(
+    check_with_base_items(
         r#"
 fn foo(a$0: Tuple) {
 }
@@ -207,7 +202,7 @@ fn foo(a$0: Tuple) {
 
 #[test]
 fn only_fn_like_macros() {
-    check_empty(
+    check(
         r#"
 macro_rules! m { ($e:expr) => { $e } }
 
@@ -228,7 +223,7 @@ fn foo() {
 
 #[test]
 fn in_simple_macro_call() {
-    check_empty(
+    check(
         r#"
 macro_rules! m { ($e:expr) => { $e } }
 enum E { X }
@@ -249,7 +244,7 @@ fn foo() {
 
 #[test]
 fn omits_private_fields_pat() {
-    check_empty(
+    check(
         r#"
 mod foo {
     pub struct Record { pub field: i32, _field: i32 }
@@ -277,7 +272,7 @@ fn outer() {
 
 #[test]
 fn completes_self_pats() {
-    check_empty(
+    check(
         r#"
 struct Foo(i32);
 impl Foo {
@@ -301,7 +296,7 @@ impl Foo {
 
 #[test]
 fn enum_qualified() {
-    check(
+    check_with_base_items(
         r#"
 impl Enum {
     type AssocType = ();
@@ -323,7 +318,7 @@ fn func() {
 
 #[test]
 fn completes_in_record_field_pat() {
-    check_empty(
+    check(
         r#"
 struct Foo { bar: Bar }
 struct Bar(u32);
@@ -342,7 +337,7 @@ fn outer(Foo { bar: $0 }: Foo) {}
 
 #[test]
 fn skips_in_record_field_pat_name() {
-    check_empty(
+    check(
         r#"
 struct Foo { bar: Bar }
 struct Bar(u32);
@@ -357,7 +352,7 @@ fn outer(Foo { bar$0 }: Foo) {}
 
 #[test]
 fn completes_in_record_field_pat_with_generic_type_alias() {
-    check_empty(
+    check(
         r#"
 type Wrap<T> = T;
 
@@ -386,7 +381,7 @@ fn main() {
 
 #[test]
 fn completes_in_fn_param() {
-    check_empty(
+    check(
         r#"
 struct Foo { bar: Bar }
 struct Bar(u32);
@@ -405,7 +400,7 @@ fn foo($0) {}
 
 #[test]
 fn completes_in_closure_param() {
-    check_empty(
+    check(
         r#"
 struct Foo { bar: Bar }
 struct Bar(u32);
@@ -426,7 +421,7 @@ fn foo() {
 
 #[test]
 fn completes_no_delims_if_existing() {
-    check_empty(
+    check(
         r#"
 struct Bar(u32);
 fn foo() {
@@ -441,7 +436,7 @@ fn foo() {
             kw self::
         "#]],
     );
-    check_empty(
+    check(
         r#"
 struct Foo { bar: u32 }
 fn foo() {
@@ -456,7 +451,7 @@ fn foo() {
             kw self::
         "#]],
     );
-    check_empty(
+    check(
         r#"
 enum Enum {
     TupleVariant(u32)
@@ -471,7 +466,7 @@ fn foo() {
             bn TupleVariant TupleVariant
         "#]],
     );
-    check_empty(
+    check(
         r#"
 enum Enum {
     RecordVariant { field: u32 }
@@ -519,7 +514,7 @@ fn foo() {
 #[test]
 fn completes_enum_variant_pat_escape() {
     cov_mark::check!(enum_variant_pattern_path);
-    check_empty(
+    check(
         r#"
 enum Enum {
     A,
@@ -544,7 +539,7 @@ fn foo() {
         "#]],
     );
 
-    check_empty(
+    check(
         r#"
 enum Enum {
     A,
@@ -569,7 +564,7 @@ fn foo() {
 
 #[test]
 fn completes_associated_const() {
-    check_empty(
+    check(
         r#"
 #[derive(PartialEq, Eq)]
 struct Ty(u8);
@@ -590,7 +585,7 @@ fn f(t: Ty) {
         "#]],
     );
 
-    check_empty(
+    check(
         r#"
 enum MyEnum {}
 
@@ -612,7 +607,7 @@ fn f(e: MyEnum) {
         "#]],
     );
 
-    check_empty(
+    check(
         r#"
 union U {
     i: i32,
@@ -637,7 +632,7 @@ fn f(u: U) {
         "#]],
     );
 
-    check_empty(
+    check(
         r#"
 #![rustc_coherence_is_core]
 #[lang = "u32"]
@@ -659,7 +654,7 @@ fn f(v: u32) {
 
 #[test]
 fn in_method_param() {
-    check_empty(
+    check(
         r#"
 struct Ty(u8);
 
@@ -680,7 +675,7 @@ impl Ty {
             kw ref
         "#]],
     );
-    check_empty(
+    check(
         r#"
 struct Ty(u8);
 
@@ -701,7 +696,7 @@ impl Ty {
             kw ref
         "#]],
     );
-    check_empty(
+    check(
         r#"
 struct Ty(u8);
 
@@ -722,7 +717,7 @@ impl Ty {
             kw ref
         "#]],
     );
-    check_empty(
+    check(
         r#"
 struct Ty(u8);
 
@@ -743,7 +738,7 @@ impl Ty {
 
 #[test]
 fn through_alias() {
-    check_empty(
+    check(
         r#"
 enum Enum<T> {
     Unit,
@@ -770,7 +765,7 @@ fn f(x: EnumAlias<u8>) {
 
 #[test]
 fn pat_no_unstable_item_on_stable() {
-    check_empty(
+    check(
         r#"
 //- /main.rs crate:main deps:std
 use std::*;
@@ -795,7 +790,7 @@ pub enum Enum {
 
 #[test]
 fn pat_unstable_item_on_nightly() {
-    check_empty(
+    check(
         r#"
 //- toolchain:nightly
 //- /main.rs crate:main deps:std
@@ -908,7 +903,7 @@ fn foo() {
     );
 
     // Do not suggest reserved keywords
-    check_empty(
+    check(
         r#"
 struct Struct;
 
@@ -926,7 +921,7 @@ fn foo() {
 
 #[test]
 fn private_item_in_module_in_function_body() {
-    check_empty(
+    check(
         r#"
 fn main() {
     mod foo {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs
index c1926359efc..65036f6a224 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs
@@ -1,17 +1,12 @@
 //! Completion tests for predicates and bounds.
-use expect_test::{expect, Expect};
+use expect_test::expect;
 
-use crate::tests::{check_empty, completion_list, BASE_ITEMS_FIXTURE};
-
-fn check(ra_fixture: &str, expect: Expect) {
-    let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}\n{ra_fixture}"));
-    expect.assert_eq(&actual)
-}
+use crate::tests::{check, check_with_base_items};
 
 #[test]
 fn predicate_start() {
     // FIXME: `for` kw
-    check(
+    check_with_base_items(
         r#"
 struct Foo<'lt, T, const C: usize> where $0 {}
 "#,
@@ -34,7 +29,7 @@ struct Foo<'lt, T, const C: usize> where $0 {}
 
 #[test]
 fn bound_for_type_pred() {
-    check(
+    check_with_base_items(
         r#"
 struct Foo<'lt, T, const C: usize> where T: $0 {}
 "#,
@@ -52,7 +47,7 @@ struct Foo<'lt, T, const C: usize> where T: $0 {}
 fn bound_for_lifetime_pred() {
     // FIXME: should only show lifetimes here, that is we shouldn't get any completions here when not typing
     // a `'`
-    check(
+    check_with_base_items(
         r#"
 struct Foo<'lt, T, const C: usize> where 'lt: $0 {}
 "#,
@@ -68,7 +63,7 @@ struct Foo<'lt, T, const C: usize> where 'lt: $0 {}
 
 #[test]
 fn bound_for_for_pred() {
-    check(
+    check_with_base_items(
         r#"
 struct Foo<'lt, T, const C: usize> where for<'a> T: $0 {}
 "#,
@@ -84,7 +79,7 @@ struct Foo<'lt, T, const C: usize> where for<'a> T: $0 {}
 
 #[test]
 fn param_list_for_for_pred() {
-    check(
+    check_with_base_items(
         r#"
 struct Foo<'lt, T, const C: usize> where for<'a> $0 {}
 "#,
@@ -107,7 +102,7 @@ struct Foo<'lt, T, const C: usize> where for<'a> $0 {}
 
 #[test]
 fn pred_on_fn_in_impl() {
-    check(
+    check_with_base_items(
         r#"
 impl Record {
     fn method(self) where $0 {}
@@ -132,7 +127,7 @@ impl Record {
 
 #[test]
 fn pred_no_unstable_item_on_stable() {
-    check_empty(
+    check(
         r#"
 //- /main.rs crate:main deps:std
 use std::*;
@@ -151,7 +146,7 @@ pub trait Trait {}
 
 #[test]
 fn pred_unstable_item_on_nightly() {
-    check_empty(
+    check(
         r#"
 //- toolchain:nightly
 //- /main.rs crate:main deps:std
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/proc_macros.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/proc_macros.rs
index afc286b6fb4..6b1dfe366ce 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/proc_macros.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/proc_macros.rs
@@ -1,12 +1,7 @@
 //! Completion tests for expressions.
-use expect_test::{expect, Expect};
+use expect_test::expect;
 
-use crate::tests::completion_list;
-
-fn check(ra_fixture: &str, expect: Expect) {
-    let actual = completion_list(ra_fixture);
-    expect.assert_eq(&actual)
-}
+use crate::tests::check;
 
 #[test]
 fn complete_dot_in_attr() {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs
index d81b3d697aa..9ab66243b5c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs
@@ -4,7 +4,7 @@ use itertools::Itertools;
 
 use crate::tests::{completion_list_with_config_raw, position, TEST_CONFIG};
 
-fn check(ra_fixture: &str, expect: Expect) {
+fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let completions = completion_list_with_config_raw(TEST_CONFIG, ra_fixture, true, None);
     let (db, position) = position(ra_fixture);
     let mut actual = db.file_text(position.file_id).to_string();
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs
index a9c9f604e07..a1013b86548 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs
@@ -1,14 +1,9 @@
-use expect_test::{expect, Expect};
+use expect_test::expect;
 
-use crate::tests::completion_list;
+use crate::tests::check;
 
 use super::check_edit;
 
-fn check(ra_fixture: &str, expect: Expect) {
-    let actual = completion_list(ra_fixture);
-    expect.assert_eq(&actual);
-}
-
 #[test]
 fn without_default_impl() {
     check(
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 6cfb2231a99..2b05184bdbe 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
@@ -5,32 +5,12 @@ use ide_db::SymbolKind;
 
 use crate::{
     tests::{
-        check_edit, completion_list, completion_list_no_kw, completion_list_with_trigger_character,
+        check, check_edit, check_no_kw, check_with_trigger_character, do_completion_with_config,
+        TEST_CONFIG,
     },
     CompletionItemKind,
 };
 
-use super::{do_completion_with_config, TEST_CONFIG};
-
-fn check_no_kw(ra_fixture: &str, expect: Expect) {
-    let actual = completion_list_no_kw(ra_fixture);
-    expect.assert_eq(&actual)
-}
-
-fn check(ra_fixture: &str, expect: Expect) {
-    let actual = completion_list(ra_fixture);
-    expect.assert_eq(&actual)
-}
-
-pub(crate) fn check_with_trigger_character(
-    ra_fixture: &str,
-    trigger_character: Option<char>,
-    expect: Expect,
-) {
-    let actual = completion_list_with_trigger_character(ra_fixture, trigger_character);
-    expect.assert_eq(&actual)
-}
-
 #[test]
 fn completes_if_prefix_is_keyword() {
     check_edit(
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
index 9ea262bcc59..c7e2d058257 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
@@ -1,16 +1,11 @@
 //! Completion tests for type position.
-use expect_test::{expect, Expect};
+use expect_test::expect;
 
-use crate::tests::{check_empty, completion_list, BASE_ITEMS_FIXTURE};
-
-fn check(ra_fixture: &str, expect: Expect) {
-    let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}\n{ra_fixture}"));
-    expect.assert_eq(&actual)
-}
+use crate::tests::{check, check_with_base_items};
 
 #[test]
 fn record_field_ty() {
-    check(
+    check_with_base_items(
         r#"
 struct Foo<'lt, T, const C: usize> {
     f: $0
@@ -37,7 +32,7 @@ struct Foo<'lt, T, const C: usize> {
 
 #[test]
 fn tuple_struct_field() {
-    check(
+    check_with_base_items(
         r#"
 struct Foo<'lt, T, const C: usize>(f$0);
 "#,
@@ -65,7 +60,7 @@ struct Foo<'lt, T, const C: usize>(f$0);
 
 #[test]
 fn fn_return_type() {
-    check(
+    check_with_base_items(
         r#"
 fn x<'lt, T, const C: usize>() -> $0
 "#,
@@ -88,7 +83,7 @@ fn x<'lt, T, const C: usize>() -> $0
 
 #[test]
 fn fn_return_type_no_local_items() {
-    check(
+    check_with_base_items(
         r#"
 fn foo() -> B$0 {
     struct Bar;
@@ -118,7 +113,7 @@ fn foo() -> B$0 {
 
 #[test]
 fn inferred_type_const() {
-    check(
+    check_with_base_items(
         r#"
 struct Foo<T>(T);
 const FOO: $0 = Foo(2);
@@ -143,7 +138,7 @@ const FOO: $0 = Foo(2);
 
 #[test]
 fn inferred_type_closure_param() {
-    check(
+    check_with_base_items(
         r#"
 fn f1(f: fn(i32) -> i32) {}
 fn f2() {
@@ -169,7 +164,7 @@ fn f2() {
 
 #[test]
 fn inferred_type_closure_return() {
-    check(
+    check_with_base_items(
         r#"
 fn f1(f: fn(u64) -> u64) {}
 fn f2() {
@@ -197,7 +192,7 @@ fn f2() {
 
 #[test]
 fn inferred_type_fn_return() {
-    check(
+    check_with_base_items(
         r#"
 fn f2(x: u64) -> $0 {
     x + 5
@@ -222,7 +217,7 @@ fn f2(x: u64) -> $0 {
 
 #[test]
 fn inferred_type_fn_param() {
-    check(
+    check_with_base_items(
         r#"
 fn f1(x: i32) {}
 fn f2(x: $0) {
@@ -248,7 +243,7 @@ fn f2(x: $0) {
 
 #[test]
 fn inferred_type_not_in_the_scope() {
-    check(
+    check_with_base_items(
         r#"
 mod a {
     pub struct Foo<T>(T);
@@ -282,7 +277,7 @@ fn foo<'lt, T, const C: usize>() {
 
 #[test]
 fn inferred_type_let() {
-    check(
+    check_with_base_items(
         r#"
 struct Foo<T>(T);
 fn foo<'lt, T, const C: usize>() {
@@ -311,7 +306,7 @@ fn foo<'lt, T, const C: usize>() {
 
 #[test]
 fn body_type_pos() {
-    check(
+    check_with_base_items(
         r#"
 fn foo<'lt, T, const C: usize>() {
     let local = ();
@@ -333,7 +328,7 @@ fn foo<'lt, T, const C: usize>() {
             kw self::
         "#]],
     );
-    check(
+    check_with_base_items(
         r#"
 fn foo<'lt, T, const C: usize>() {
     let local = ();
@@ -356,7 +351,7 @@ fn foo<'lt, T, const C: usize>() {
 #[test]
 fn completes_types_and_const_in_arg_list() {
     cov_mark::check!(complete_assoc_type_in_generics_list);
-    check(
+    check_with_base_items(
         r#"
 trait Trait1 {
     type Super;
@@ -372,7 +367,7 @@ fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {}
             ta Super =  (as Trait1) type Super
         "#]],
     );
-    check(
+    check_with_base_items(
         r#"
 trait Trait1 {
     type Super;
@@ -400,7 +395,7 @@ fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {}
             kw self::
         "#]],
     );
-    check(
+    check_with_base_items(
         r#"
 trait Trait2<T> {
     type Foo;
@@ -424,7 +419,7 @@ fn foo<'lt, T: Trait2<self::$0>, const CONST_PARAM: usize>(_: T) {}
 
 #[test]
 fn no_assoc_completion_outside_type_bounds() {
-    check(
+    check_with_base_items(
         r#"
 struct S;
 trait Tr<T> {
@@ -454,7 +449,7 @@ impl Tr<$0
 
 #[test]
 fn enum_qualified() {
-    check(
+    check_with_base_items(
         r#"
 impl Enum {
     type AssocType = ();
@@ -471,7 +466,7 @@ fn func(_: Enum::$0) {}
 
 #[test]
 fn completes_type_parameter_or_associated_type() {
-    check(
+    check_with_base_items(
         r#"
 trait MyTrait<T, U> {
     type Item1;
@@ -496,7 +491,7 @@ fn f(t: impl MyTrait<u$0
         "#]],
     );
 
-    check(
+    check_with_base_items(
         r#"
 trait MyTrait<T, U> {
     type Item1;
@@ -521,7 +516,7 @@ fn f(t: impl MyTrait<u8, u$0
         "#]],
     );
 
-    check(
+    check_with_base_items(
         r#"
 trait MyTrait<T, U> {
     type Item1;
@@ -539,7 +534,7 @@ fn f(t: impl MyTrait<u8, u8, I$0
 
 #[test]
 fn completes_type_parameter_or_associated_type_with_default_value() {
-    check(
+    check_with_base_items(
         r#"
 trait MyTrait<T, U = u8> {
     type Item1;
@@ -564,7 +559,7 @@ fn f(t: impl MyTrait<u$0
         "#]],
     );
 
-    check(
+    check_with_base_items(
         r#"
 trait MyTrait<T, U = u8> {
     type Item1;
@@ -591,7 +586,7 @@ fn f(t: impl MyTrait<u8, u$0
         "#]],
     );
 
-    check(
+    check_with_base_items(
         r#"
 trait MyTrait<T, U = u8> {
     type Item1;
@@ -609,7 +604,7 @@ fn f(t: impl MyTrait<u8, u8, I$0
 
 #[test]
 fn completes_types_after_associated_type() {
-    check(
+    check_with_base_items(
         r#"
 trait MyTrait {
     type Item1;
@@ -634,7 +629,7 @@ fn f(t: impl MyTrait<Item1 = $0
         "#]],
     );
 
-    check(
+    check_with_base_items(
         r#"
 trait MyTrait {
     type Item1;
@@ -659,7 +654,7 @@ fn f(t: impl MyTrait<Item1 = u8, Item2 = $0
         "#]],
     );
 
-    check(
+    check_with_base_items(
         r#"
 trait MyTrait {
     const C: usize;
@@ -678,7 +673,7 @@ fn f(t: impl MyTrait<C = $0
 
 #[test]
 fn type_pos_no_unstable_type_on_stable() {
-    check_empty(
+    check(
         r#"
 //- /main.rs crate:main deps:std
 use std::*;
@@ -702,7 +697,7 @@ pub struct S;
 
 #[test]
 fn type_pos_unstable_type_on_nightly() {
-    check_empty(
+    check(
         r#"
 //- toolchain:nightly
 //- /main.rs crate:main deps:std
@@ -729,7 +724,7 @@ pub struct S;
 #[test]
 fn completes_const_and_type_generics_separately() {
     // Function generic params
-    check(
+    check_with_base_items(
         r#"
     struct Foo;
     const X: usize = 0;
@@ -756,7 +751,7 @@ fn completes_const_and_type_generics_separately() {
     // FIXME: This should probably also suggest completions for types, at least those that have
     // associated constants usable in this position. For example, a user could be typing
     // `foo::<_, { usize::MAX }>()`, but we currently don't suggest `usize` in constant position.
-    check(
+    check_with_base_items(
         r#"
     struct Foo;
     const X: usize = 0;
@@ -775,7 +770,7 @@ fn completes_const_and_type_generics_separately() {
     );
 
     // Method generic params
-    check(
+    check_with_base_items(
         r#"
     const X: usize = 0;
     struct Foo;
@@ -799,7 +794,7 @@ fn completes_const_and_type_generics_separately() {
             kw self::
         "#]],
     );
-    check(
+    check_with_base_items(
         r#"
     const X: usize = 0;
     struct Foo;
@@ -818,7 +813,7 @@ fn completes_const_and_type_generics_separately() {
     );
 
     // Associated type generic params
-    check(
+    check_with_base_items(
         r#"
     const X: usize = 0;
     struct Foo;
@@ -843,7 +838,7 @@ fn completes_const_and_type_generics_separately() {
             kw self::
         "#]],
     );
-    check(
+    check_with_base_items(
         r#"
     const X: usize = 0;
     struct Foo;
@@ -862,7 +857,7 @@ fn completes_const_and_type_generics_separately() {
     );
 
     // Type generic params
-    check(
+    check_with_base_items(
         r#"
     const X: usize = 0;
     struct Foo<T, const N: usize>(T);
@@ -880,7 +875,7 @@ fn completes_const_and_type_generics_separately() {
     );
 
     // Type alias generic params
-    check(
+    check_with_base_items(
         r#"
     const X: usize = 0;
     struct Foo<T, const N: usize>(T);
@@ -899,7 +894,7 @@ fn completes_const_and_type_generics_separately() {
     );
 
     // Enum variant params
-    check(
+    check_with_base_items(
         r#"
     const X: usize = 0;
     enum Foo<T, const N: usize> { A(T), B }
@@ -917,7 +912,7 @@ fn completes_const_and_type_generics_separately() {
     );
 
     // Trait params
-    check(
+    check_with_base_items(
         r#"
     const X: usize = 0;
     trait Foo<T, const N: usize> {}
@@ -933,7 +928,7 @@ fn completes_const_and_type_generics_separately() {
     );
 
     // Trait alias params
-    check(
+    check_with_base_items(
         r#"
     #![feature(trait_alias)]
     const X: usize = 0;
@@ -951,7 +946,7 @@ fn completes_const_and_type_generics_separately() {
     );
 
     // Omitted lifetime params
-    check(
+    check_with_base_items(
         r#"
 struct S<'a, 'b, const C: usize, T>(core::marker::PhantomData<&'a &'b T>);
 fn foo<'a>() { S::<F$0, _>; }
@@ -964,7 +959,7 @@ fn foo<'a>() { S::<F$0, _>; }
         "#]],
     );
     // Explicit lifetime params
-    check(
+    check_with_base_items(
         r#"
 struct S<'a, 'b, const C: usize, T>(core::marker::PhantomData<&'a &'b T>);
 fn foo<'a>() { S::<'static, 'static, F$0, _>; }
@@ -976,7 +971,7 @@ fn foo<'a>() { S::<'static, 'static, F$0, _>; }
             kw self::
         "#]],
     );
-    check(
+    check_with_base_items(
         r#"
 struct S<'a, 'b, const C: usize, T>(core::marker::PhantomData<&'a &'b T>);
 fn foo<'a>() { S::<'static, F$0, _, _>; }
@@ -992,7 +987,7 @@ fn foo<'a>() { S::<'static, F$0, _, _>; }
 
 #[test]
 fn complete_traits_on_impl_trait_block() {
-    check(
+    check_with_base_items(
         r#"
 trait Foo {}
 
@@ -1012,7 +1007,7 @@ impl $0 for Bar { }
 
 #[test]
 fn complete_traits_with_path_on_impl_trait_block() {
-    check(
+    check_with_base_items(
         r#"
 mod outer {
     pub trait Foo {}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs
index 2ea2e4e4c96..04b3a47a64d 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs
@@ -1,12 +1,7 @@
 //! Completion tests for use trees.
-use expect_test::{expect, Expect};
+use expect_test::expect;
 
-use crate::tests::completion_list;
-
-fn check(ra_fixture: &str, expect: Expect) {
-    let actual = completion_list(ra_fixture);
-    expect.assert_eq(&actual)
-}
+use crate::tests::check;
 
 #[test]
 fn use_tree_completion() {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs
index c18d6e66dd6..4b5a0ac1c2b 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs
@@ -1,17 +1,7 @@
 //! Completion tests for visibility modifiers.
-use expect_test::{expect, Expect};
+use expect_test::expect;
 
-use crate::tests::{completion_list, completion_list_with_trigger_character};
-
-fn check(ra_fixture: &str, expect: Expect) {
-    let actual = completion_list(ra_fixture);
-    expect.assert_eq(&actual)
-}
-
-fn check_with_trigger_character(ra_fixture: &str, trigger_character: char, expect: Expect) {
-    let actual = completion_list_with_trigger_character(ra_fixture, Some(trigger_character));
-    expect.assert_eq(&actual)
-}
+use crate::tests::{check, check_with_trigger_character};
 
 #[test]
 fn empty_pub() {
@@ -20,7 +10,7 @@ fn empty_pub() {
         r#"
 pub($0)
 "#,
-        '(',
+        Some('('),
         expect![[r#"
             kw crate
             kw in
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs
index 7482491fc63..11808fed3be 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs
@@ -4,7 +4,7 @@ use either::Either;
 use hir::{InFile, Semantics, Type};
 use parser::T;
 use syntax::{
-    ast::{self, HasArgList, HasName},
+    ast::{self, AstChildren, HasArgList, HasAttrs, HasName},
     match_ast, AstNode, NodeOrToken, SyntaxToken,
 };
 
@@ -37,6 +37,10 @@ impl ActiveParameter {
             _ => None,
         })
     }
+
+    pub fn attrs(&self) -> Option<AstChildren<ast::Attr>> {
+        self.src.as_ref().and_then(|param| Some(param.value.as_ref().right()?.attrs()))
+    }
 }
 
 /// Returns a [`hir::Callable`] this token is a part of and its argument index of said callable.
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 2d30bb41273..49d26dfe25c 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -32,6 +32,7 @@ pub enum Definition {
     Field(Field),
     TupleField(TupleField),
     Module(Module),
+    Crate(Crate),
     Function(Function),
     Adt(Adt),
     Variant(Variant),
@@ -62,14 +63,19 @@ impl Definition {
     pub fn krate(&self, db: &RootDatabase) -> Option<Crate> {
         Some(match self {
             Definition::Module(m) => m.krate(),
+            &Definition::Crate(it) => it,
             _ => self.module(db)?.krate(),
         })
     }
 
+    /// Returns the module this definition resides in.
+    ///
+    /// As such, for modules themselves this will return the parent module.
     pub fn module(&self, db: &RootDatabase) -> Option<Module> {
         let module = match self {
             Definition::Macro(it) => it.module(db),
             Definition::Module(it) => it.parent(db)?,
+            Definition::Crate(_) => return None,
             Definition::Field(it) => it.parent_def(db).module(db),
             Definition::Function(it) => it.module(db),
             Definition::Adt(it) => it.module(db),
@@ -86,11 +92,11 @@ impl Definition {
             Definition::ExternCrateDecl(it) => it.module(db),
             Definition::DeriveHelper(it) => it.derive().module(db),
             Definition::InlineAsmOperand(it) => it.parent(db).module(db),
+            Definition::ToolModule(t) => t.krate().root_module(),
             Definition::BuiltinAttr(_)
             | Definition::BuiltinType(_)
             | Definition::BuiltinLifetime(_)
             | Definition::TupleField(_)
-            | Definition::ToolModule(_)
             | Definition::InlineAsmRegOrRegClass(_) => return None,
         };
         Some(module)
@@ -108,6 +114,7 @@ impl Definition {
         match self {
             Definition::Macro(it) => Some(it.module(db).into()),
             Definition::Module(it) => it.parent(db).map(Definition::Module),
+            Definition::Crate(_) => None,
             Definition::Field(it) => Some(it.parent_def(db).into()),
             Definition::Function(it) => container_to_definition(it.container(db)),
             Definition::Adt(it) => Some(it.module(db).into()),
@@ -137,6 +144,7 @@ impl Definition {
         let vis = match self {
             Definition::Field(sf) => sf.visibility(db),
             Definition::Module(it) => it.visibility(db),
+            Definition::Crate(_) => return None,
             Definition::Function(it) => it.visibility(db),
             Definition::Adt(it) => it.visibility(db),
             Definition::Const(it) => it.visibility(db),
@@ -146,8 +154,8 @@ impl Definition {
             Definition::TypeAlias(it) => it.visibility(db),
             Definition::Variant(it) => it.visibility(db),
             Definition::ExternCrateDecl(it) => it.visibility(db),
+            Definition::Macro(it) => it.visibility(db),
             Definition::BuiltinType(_) | Definition::TupleField(_) => Visibility::Public,
-            Definition::Macro(_) => return None,
             Definition::BuiltinAttr(_)
             | Definition::BuiltinLifetime(_)
             | Definition::ToolModule(_)
@@ -167,6 +175,9 @@ impl Definition {
             Definition::Macro(it) => it.name(db),
             Definition::Field(it) => it.name(db),
             Definition::Module(it) => it.name(db)?,
+            Definition::Crate(it) => {
+                Name::new_symbol_root(it.display_name(db)?.crate_name().symbol().clone())
+            }
             Definition::Function(it) => it.name(db),
             Definition::Adt(it) => it.name(db),
             Definition::Variant(it) => it.name(db),
@@ -202,6 +213,7 @@ impl Definition {
             Definition::Macro(it) => it.docs(db),
             Definition::Field(it) => it.docs(db),
             Definition::Module(it) => it.docs(db),
+            Definition::Crate(it) => it.docs(db),
             Definition::Function(it) => it.docs(db),
             Definition::Adt(it) => it.docs(db),
             Definition::Variant(it) => it.docs(db),
@@ -282,6 +294,7 @@ impl Definition {
             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(),
@@ -415,7 +428,7 @@ impl IdentClass {
             }
             IdentClass::NameRefClass(NameRefClass::ExternCrateShorthand { decl, krate }) => {
                 res.push((Definition::ExternCrateDecl(decl), None));
-                res.push((Definition::Module(krate.root_module()), None));
+                res.push((Definition::Crate(krate), None));
             }
             IdentClass::Operator(
                 OperatorClass::Await(func)
@@ -456,7 +469,7 @@ impl IdentClass {
             }
             IdentClass::NameRefClass(NameRefClass::ExternCrateShorthand { decl, krate }) => {
                 res.push(Definition::ExternCrateDecl(decl));
-                res.push(Definition::Module(krate.root_module()));
+                res.push(Definition::Crate(krate));
             }
             IdentClass::Operator(_) => (),
         }
@@ -800,7 +813,7 @@ impl NameRefClass {
                     let extern_crate = sema.to_def(&extern_crate_ast)?;
                     let krate = extern_crate.resolved_crate(sema.db)?;
                     Some(if extern_crate_ast.rename().is_some() {
-                        NameRefClass::Definition(Definition::Module(krate.root_module()), None)
+                        NameRefClass::Definition(Definition::Crate(krate), None)
                     } else {
                         NameRefClass::ExternCrateShorthand { krate, decl: extern_crate }
                     })
@@ -976,3 +989,19 @@ impl From<GenericDef> for Definition {
         }
     }
 }
+
+impl TryFrom<Definition> for GenericDef {
+    type Error = ();
+    fn try_from(def: Definition) -> Result<Self, Self::Error> {
+        match def {
+            Definition::Function(it) => Ok(it.into()),
+            Definition::Adt(it) => Ok(it.into()),
+            Definition::Trait(it) => Ok(it.into()),
+            Definition::TraitAlias(it) => Ok(it.into()),
+            Definition::TypeAlias(it) => Ok(it.into()),
+            Definition::SelfType(it) => Ok(it.into()),
+            Definition::Const(it) => Ok(it.into()),
+            _ => Err(()),
+        }
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs
index a0ef0f90a65..b83efcd02f7 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs
@@ -178,7 +178,7 @@ macro_rules! impl_has_docs {
 
 impl_has_docs![
     Variant, Field, Static, Const, Trait, TraitAlias, TypeAlias, Macro, Function, Adt, Module,
-    Impl,
+    Impl, Crate,
 ];
 
 macro_rules! impl_has_docs_enum {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
index ba6e50abf65..9e3506d6f53 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
@@ -106,6 +106,10 @@ impl FamousDefs<'_, '_> {
         self.find_trait("core:marker:Copy")
     }
 
+    pub fn core_marker_Sized(&self) -> Option<Trait> {
+        self.find_trait("core:marker:Sized")
+    }
+
     pub fn core_future_Future(&self) -> Option<Trait> {
         self.find_trait("core:future:Future")
     }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
index 8f0be1d9035..ad86d855b55 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
@@ -1,15 +1,17 @@
 //! Look up accessible paths for items.
 
+use std::ops::ControlFlow;
+
 use hir::{
     db::HirDatabase, AsAssocItem, AssocItem, AssocItemContainer, Crate, HasCrate, ImportPathConfig,
-    ItemInNs, ModPath, Module, ModuleDef, PathResolution, PrefixKind, ScopeDef, Semantics,
+    ItemInNs, ModPath, Module, ModuleDef, Name, PathResolution, PrefixKind, ScopeDef, Semantics,
     SemanticsScope, Trait, TyFingerprint, Type,
 };
 use itertools::Itertools;
 use rustc_hash::{FxHashMap, FxHashSet};
 use syntax::{
     ast::{self, make, HasName},
-    AstNode, SmolStr, SyntaxNode,
+    AstNode, SyntaxNode,
 };
 
 use crate::{
@@ -51,7 +53,7 @@ pub struct TraitImportCandidate {
 #[derive(Debug)]
 pub struct PathImportCandidate {
     /// Optional qualifier before name.
-    pub qualifier: Vec<SmolStr>,
+    pub qualifier: Vec<Name>,
     /// The name the item (struct, trait, enum, etc.) should have.
     pub name: NameToImport,
 }
@@ -70,10 +72,18 @@ pub enum NameToImport {
 
 impl NameToImport {
     pub fn exact_case_sensitive(s: String) -> NameToImport {
+        let s = match s.strip_prefix("r#") {
+            Some(s) => s.to_owned(),
+            None => s,
+        };
         NameToImport::Exact(s, true)
     }
 
     pub fn fuzzy(s: String) -> NameToImport {
+        let s = match s.strip_prefix("r#") {
+            Some(s) => s.to_owned(),
+            None => s,
+        };
         // unless all chars are lowercase, we do a case sensitive search
         let case_sensitive = s.chars().any(|c| c.is_uppercase());
         NameToImport::Fuzzy(s, case_sensitive)
@@ -350,21 +360,27 @@ fn path_applicable_imports(
             .take(DEFAULT_QUERY_SEARCH_LIMIT.inner())
             .collect()
         }
+        // we have some unresolved qualifier that we search an import for
+        // The key here is that whatever we import must form a resolved path for the remainder of
+        // what follows
+        // FIXME: This doesn't handle visibility
         [first_qsegment, qualifier_rest @ ..] => items_locator::items_with_name(
             sema,
             current_crate,
-            NameToImport::Exact(first_qsegment.to_string(), true),
+            NameToImport::Exact(first_qsegment.as_str().to_owned(), true),
             AssocSearchMode::Exclude,
         )
         .filter_map(|item| {
-            import_for_item(
+            // we found imports for `first_qsegment`, now we need to filter these imports by whether
+            // they result in resolving the rest of the path successfully
+            validate_resolvable(
                 sema,
                 scope,
                 mod_path,
+                scope_filter,
                 &path_candidate.name,
                 item,
                 qualifier_rest,
-                scope_filter,
             )
         })
         .take(DEFAULT_QUERY_SEARCH_LIMIT.inner())
@@ -372,14 +388,16 @@ fn path_applicable_imports(
     }
 }
 
-fn import_for_item(
+/// Validates and builds an import for `resolved_qualifier` if the `unresolved_qualifier` appended
+/// to it resolves and there is a validate `candidate` after that.
+fn validate_resolvable(
     sema: &Semantics<'_, RootDatabase>,
     scope: &SemanticsScope<'_>,
     mod_path: impl Fn(ItemInNs) -> Option<ModPath>,
+    scope_filter: impl Fn(ItemInNs) -> bool,
     candidate: &NameToImport,
     resolved_qualifier: ItemInNs,
-    unresolved_qualifier: &[SmolStr],
-    scope_filter: impl Fn(ItemInNs) -> bool,
+    unresolved_qualifier: &[Name],
 ) -> Option<LocatedImport> {
     let _p = tracing::info_span!("ImportAssets::import_for_item").entered();
 
@@ -410,8 +428,11 @@ fn import_for_item(
                 module,
                 candidate.clone(),
                 AssocSearchMode::Exclude,
+                |it| match scope_filter(it) {
+                    true => ControlFlow::Break(it),
+                    false => ControlFlow::Continue(()),
+                },
             )
-            .find(|&it| scope_filter(it))
             .map(|item| LocatedImport::new(import_path_candidate, resolved_qualifier, item))
         }
         // FIXME
@@ -709,7 +730,7 @@ fn path_import_candidate(
                 if qualifier.first_qualifier().is_none_or(|it| sema.resolve_path(&it).is_none()) {
                     let qualifier = qualifier
                         .segments()
-                        .map(|seg| seg.name_ref().map(|name| SmolStr::new(name.text())))
+                        .map(|seg| seg.name_ref().map(|name| Name::new_root(&name.text())))
                         .collect::<Option<Vec<_>>>()?;
                     ImportCandidate::Path(PathImportCandidate { qualifier, name })
                 } else {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs
index 81604b55272..decb0ea9d8a 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs
@@ -1244,8 +1244,8 @@ use ::ext::foo::Foo;
 
 fn check_with_config(
     path: &str,
-    ra_fixture_before: &str,
-    ra_fixture_after: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
     config: &InsertUseConfig,
 ) {
     let (db, file_id, pos) = if ra_fixture_before.contains(CURSOR_MARKER) {
@@ -1277,8 +1277,8 @@ fn check_with_config(
 
 fn check(
     path: &str,
-    ra_fixture_before: &str,
-    ra_fixture_after: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
     granularity: ImportGranularity,
 ) {
     check_with_config(
@@ -1295,19 +1295,35 @@ fn check(
     )
 }
 
-fn check_crate(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
+fn check_crate(
+    path: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
+) {
     check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Crate)
 }
 
-fn check_module(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
+fn check_module(
+    path: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
+) {
     check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Module)
 }
 
-fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
+fn check_none(
+    path: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
+) {
     check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Item)
 }
 
-fn check_one(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
+fn check_one(
+    path: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
+) {
     check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::One)
 }
 
@@ -1330,7 +1346,7 @@ fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior
     assert_eq!(result.map(|u| u.to_string()), None);
 }
 
-fn check_guess(ra_fixture: &str, expected: ImportGranularityGuess) {
+fn check_guess(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected: ImportGranularityGuess) {
     let syntax = ast::SourceFile::parse(ra_fixture, span::Edition::CURRENT).tree().syntax().clone();
     let file = ImportScope::from(syntax).unwrap();
     assert_eq!(super::guess_granularity_from_scope(&file), expected);
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs b/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs
index 7f66ea0c103..a2062f36d3f 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs
@@ -2,6 +2,8 @@
 //! by its name and a few criteria.
 //! The main reason for this module to exist is the fact that project's items and dependencies' items
 //! are located in different caches, with different APIs.
+use std::ops::ControlFlow;
+
 use either::Either;
 use hir::{import_map, Crate, ItemInNs, Module, Semantics};
 use limit::Limit;
@@ -17,6 +19,7 @@ pub static DEFAULT_QUERY_SEARCH_LIMIT: Limit = Limit::new(100);
 
 pub use import_map::AssocSearchMode;
 
+// FIXME: Do callbacks instead to avoid allocations.
 /// Searches for importable items with the given name in the crate and its dependencies.
 pub fn items_with_name<'a>(
     sema: &'a Semantics<'_, RootDatabase>,
@@ -70,12 +73,13 @@ pub fn items_with_name<'a>(
 }
 
 /// Searches for importable items with the given name in the crate and its dependencies.
-pub fn items_with_name_in_module<'a>(
-    sema: &'a Semantics<'_, RootDatabase>,
+pub fn items_with_name_in_module<T>(
+    sema: &Semantics<'_, RootDatabase>,
     module: Module,
     name: NameToImport,
     assoc_item_search: AssocSearchMode,
-) -> impl Iterator<Item = ItemInNs> + 'a {
+    mut cb: impl FnMut(ItemInNs) -> ControlFlow<T>,
+) -> Option<T> {
     let _p = tracing::info_span!("items_with_name_in", name = name.text(), assoc_item_search = ?assoc_item_search, ?module)
         .entered();
 
@@ -107,14 +111,12 @@ pub fn items_with_name_in_module<'a>(
             local_query
         }
     };
-    let mut local_results = Vec::new();
     local_query.search(&[sema.db.module_symbols(module)], |local_candidate| {
-        local_results.push(match local_candidate.def {
+        cb(match local_candidate.def {
             hir::ModuleDef::Macro(macro_def) => ItemInNs::Macros(macro_def),
             def => ItemInNs::from(def),
         })
-    });
-    local_results.into_iter()
+    })
 }
 
 fn find_items<'a>(
@@ -142,7 +144,8 @@ fn find_items<'a>(
         local_results.push(match local_candidate.def {
             hir::ModuleDef::Macro(macro_def) => ItemInNs::Macros(macro_def),
             def => ItemInNs::from(def),
-        })
+        });
+        ControlFlow::<()>::Continue(())
     });
     local_results.into_iter().chain(external_importables)
 }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
index b3105e6524d..3a29232d331 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
@@ -260,23 +260,23 @@ impl From<hir::MacroKind> for SymbolKind {
     }
 }
 
-impl From<hir::ModuleDefId> for SymbolKind {
-    fn from(it: hir::ModuleDefId) -> Self {
+impl From<hir::ModuleDef> for SymbolKind {
+    fn from(it: hir::ModuleDef) -> Self {
         match it {
-            hir::ModuleDefId::ConstId(..) => SymbolKind::Const,
-            hir::ModuleDefId::EnumVariantId(..) => SymbolKind::Variant,
-            hir::ModuleDefId::FunctionId(..) => SymbolKind::Function,
-            hir::ModuleDefId::MacroId(hir::MacroId::ProcMacroId(..)) => SymbolKind::ProcMacro,
-            hir::ModuleDefId::MacroId(..) => SymbolKind::Macro,
-            hir::ModuleDefId::ModuleId(..) => SymbolKind::Module,
-            hir::ModuleDefId::StaticId(..) => SymbolKind::Static,
-            hir::ModuleDefId::AdtId(hir::AdtId::StructId(..)) => SymbolKind::Struct,
-            hir::ModuleDefId::AdtId(hir::AdtId::EnumId(..)) => SymbolKind::Enum,
-            hir::ModuleDefId::AdtId(hir::AdtId::UnionId(..)) => SymbolKind::Union,
-            hir::ModuleDefId::TraitId(..) => SymbolKind::Trait,
-            hir::ModuleDefId::TraitAliasId(..) => SymbolKind::TraitAlias,
-            hir::ModuleDefId::TypeAliasId(..) => SymbolKind::TypeAlias,
-            hir::ModuleDefId::BuiltinType(..) => SymbolKind::TypeAlias,
+            hir::ModuleDef::Const(..) => SymbolKind::Const,
+            hir::ModuleDef::Variant(..) => SymbolKind::Variant,
+            hir::ModuleDef::Function(..) => SymbolKind::Function,
+            hir::ModuleDef::Macro(mac) if mac.is_proc_macro() => SymbolKind::ProcMacro,
+            hir::ModuleDef::Macro(..) => SymbolKind::Macro,
+            hir::ModuleDef::Module(..) => SymbolKind::Module,
+            hir::ModuleDef::Static(..) => SymbolKind::Static,
+            hir::ModuleDef::Adt(hir::Adt::Struct(..)) => SymbolKind::Struct,
+            hir::ModuleDef::Adt(hir::Adt::Enum(..)) => SymbolKind::Enum,
+            hir::ModuleDef::Adt(hir::Adt::Union(..)) => SymbolKind::Union,
+            hir::ModuleDef::Trait(..) => SymbolKind::Trait,
+            hir::ModuleDef::TraitAlias(..) => SymbolKind::TraitAlias,
+            hir::ModuleDef::TypeAlias(..) => SymbolKind::TypeAlias,
+            hir::ModuleDef::BuiltinType(..) => SymbolKind::TypeAlias,
         }
     }
 }
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 1d1679c3ff8..42efbd68e33 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
@@ -134,6 +134,7 @@ impl Definition {
                     FieldSource::Pos(_) => None,
                 }
             }
+            Definition::Crate(_) => None,
             Definition::Module(module) => {
                 let src = module.declaration_source(sema.db)?;
                 let name = src.value.name()?;
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
index 68199dd8711..a75aba137be 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
@@ -953,14 +953,19 @@ impl<'a> FindUsages<'a> {
 
             // Search for occurrences of the items name
             for offset in Self::match_indices(&text, finder, search_range) {
-                tree.token_at_offset(offset).for_each(|token| {
-                    let Some(str_token) = ast::String::cast(token.clone()) else { return };
+                let ret = tree.token_at_offset(offset).any(|token| {
+                    let Some(str_token) = ast::String::cast(token.clone()) else { return false };
                     if let Some((range, Some(nameres))) =
                         sema.check_for_format_args_template(token, offset)
                     {
-                        if self.found_format_args_ref(file_id, range, str_token, nameres, sink) {}
+                        return self
+                            .found_format_args_ref(file_id, range, str_token, nameres, sink);
                     }
+                    false
                 });
+                if ret {
+                    return;
+                }
 
                 for name in
                     Self::find_nodes(sema, name, &tree, offset).filter_map(ast::NameLike::cast)
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 94d354d28e5..c94644eeb89 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
@@ -25,6 +25,7 @@ use std::{
     fmt,
     hash::{Hash, Hasher},
     mem,
+    ops::ControlFlow,
 };
 
 use base_db::{
@@ -136,16 +137,13 @@ fn library_symbols(db: &dyn SymbolsDatabase, source_root_id: SourceRootId) -> Ar
         // the module or crate indices for those in salsa unless we need to.
         .for_each(|module| symbol_collector.collect(module));
 
-    let mut symbols = symbol_collector.finish();
-    symbols.shrink_to_fit();
-    Arc::new(SymbolIndex::new(symbols))
+    Arc::new(SymbolIndex::new(symbol_collector.finish()))
 }
 
 fn module_symbols(db: &dyn SymbolsDatabase, module: Module) -> Arc<SymbolIndex> {
     let _p = tracing::info_span!("module_symbols").entered();
 
-    let symbols = SymbolCollector::collect_module(db.upcast(), module);
-    Arc::new(SymbolIndex::new(symbols))
+    Arc::new(SymbolIndex::new(SymbolCollector::collect_module(db.upcast(), module)))
 }
 
 pub fn crate_symbols(db: &dyn SymbolsDatabase, krate: Crate) -> Box<[Arc<SymbolIndex>]> {
@@ -222,13 +220,16 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
     };
 
     let mut res = vec![];
-    query.search(&indices, |f| res.push(f.clone()));
+    query.search::<()>(&indices, |f| {
+        res.push(f.clone());
+        ControlFlow::Continue(())
+    });
     res
 }
 
 #[derive(Default)]
 pub struct SymbolIndex {
-    symbols: Vec<FileSymbol>,
+    symbols: Box<[FileSymbol]>,
     map: fst::Map<Vec<u8>>,
 }
 
@@ -253,10 +254,10 @@ impl Hash for SymbolIndex {
 }
 
 impl SymbolIndex {
-    fn new(mut symbols: Vec<FileSymbol>) -> SymbolIndex {
+    fn new(mut symbols: Box<[FileSymbol]>) -> SymbolIndex {
         fn cmp(lhs: &FileSymbol, rhs: &FileSymbol) -> Ordering {
-            let lhs_chars = lhs.name.chars().map(|c| c.to_ascii_lowercase());
-            let rhs_chars = rhs.name.chars().map(|c| c.to_ascii_lowercase());
+            let lhs_chars = lhs.name.as_str().chars().map(|c| c.to_ascii_lowercase());
+            let rhs_chars = rhs.name.as_str().chars().map(|c| c.to_ascii_lowercase());
             lhs_chars.cmp(rhs_chars)
         }
 
@@ -316,11 +317,11 @@ impl SymbolIndex {
 }
 
 impl Query {
-    pub(crate) fn search<'sym>(
+    pub(crate) fn search<'sym, T>(
         self,
         indices: &'sym [Arc<SymbolIndex>],
-        cb: impl FnMut(&'sym FileSymbol),
-    ) {
+        cb: impl FnMut(&'sym FileSymbol) -> ControlFlow<T>,
+    ) -> Option<T> {
         let _p = tracing::info_span!("symbol_index::Query::search").entered();
         let mut op = fst::map::OpBuilder::new();
         match self.mode {
@@ -351,12 +352,12 @@ impl Query {
         }
     }
 
-    fn search_maps<'sym>(
+    fn search_maps<'sym, T>(
         &self,
         indices: &'sym [Arc<SymbolIndex>],
         mut stream: fst::map::Union<'_>,
-        mut cb: impl FnMut(&'sym FileSymbol),
-    ) {
+        mut cb: impl FnMut(&'sym FileSymbol) -> ControlFlow<T>,
+    ) -> Option<T> {
         let ignore_underscore_prefixed = !self.query.starts_with("__");
         while let Some((_, indexed_values)) = stream.next() {
             for &IndexedValue { index, value } in indexed_values {
@@ -377,15 +378,19 @@ impl Query {
                         continue;
                     }
                     // Hide symbols that start with `__` unless the query starts with `__`
-                    if ignore_underscore_prefixed && symbol.name.starts_with("__") {
+                    let symbol_name = symbol.name.as_str();
+                    if ignore_underscore_prefixed && symbol_name.starts_with("__") {
                         continue;
                     }
-                    if self.mode.check(&self.query, self.case_sensitive, &symbol.name) {
-                        cb(symbol);
+                    if self.mode.check(&self.query, self.case_sensitive, symbol_name) {
+                        if let Some(b) = cb(symbol).break_value() {
+                            return Some(b);
+                        }
                     }
                 }
             }
         }
+        None
     }
 
     fn matches_assoc_mode(&self, is_trait_assoc_item: bool) -> bool {
@@ -476,9 +481,9 @@ use Macro as ItemLikeMacro;
 use Macro as Trait; // overlay namespaces
 //- /b_mod.rs
 struct StructInModB;
-use super::Macro as SuperItemLikeMacro;
-use crate::b_mod::StructInModB as ThisStruct;
-use crate::Trait as IsThisJustATrait;
+pub(self) use super::Macro as SuperItemLikeMacro;
+pub(self) use crate::b_mod::StructInModB as ThisStruct;
+pub(self) use crate::Trait as IsThisJustATrait;
 "#,
         );
 
@@ -487,7 +492,7 @@ use crate::Trait as IsThisJustATrait;
             .into_iter()
             .map(|module_id| {
                 let mut symbols = SymbolCollector::collect_module(&db, module_id);
-                symbols.sort_by_key(|it| it.name.clone());
+                symbols.sort_by_key(|it| it.name.as_str().to_owned());
                 (module_id, symbols)
             })
             .collect();
@@ -514,7 +519,7 @@ struct Duplicate;
             .into_iter()
             .map(|module_id| {
                 let mut symbols = SymbolCollector::collect_module(&db, module_id);
-                symbols.sort_by_key(|it| it.name.clone());
+                symbols.sort_by_key(|it| it.name.as_str().to_owned());
                 (module_id, symbols)
             })
             .collect();
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
index 365d726d2a9..557c95f704b 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
@@ -421,7 +421,7 @@ mod tests {
     use super::*;
 
     #[track_caller]
-    fn check(ra_fixture: &str, expected: &str) {
+    fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected: &str) {
         let (db, file_id, range_or_offset) = RootDatabase::with_range_or_offset(ra_fixture);
         let frange = FileRange { file_id, range: range_or_offset.into() };
 
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
index 9d70942199c..535777dfcbe 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
@@ -631,7 +631,7 @@
                 def: Function(
                     Function {
                         id: FunctionId(
-                            3,
+                            2,
                         ),
                     },
                 ),
@@ -664,7 +664,7 @@
                 def: Function(
                     Function {
                         id: FunctionId(
-                            2,
+                            1,
                         ),
                     },
                 ),
@@ -794,7 +794,7 @@
                 def: Function(
                     Function {
                         id: FunctionId(
-                            1,
+                            3,
                         ),
                     },
                 ),
@@ -879,12 +879,10 @@
         [
             FileSymbol {
                 name: "IsThisJustATrait",
-                def: Macro(
-                    Macro {
-                        id: Macro2Id(
-                            Macro2Id(
-                                0,
-                            ),
+                def: Trait(
+                    Trait {
+                        id: TraitId(
+                            0,
                         ),
                     },
                 ),
@@ -897,12 +895,12 @@
                     ),
                     ptr: SyntaxNodePtr {
                         kind: USE_TREE,
-                        range: 111..143,
+                        range: 141..173,
                     },
                     name_ptr: AstPtr(
                         SyntaxNodePtr {
                             kind: NAME,
-                            range: 127..143,
+                            range: 157..173,
                         },
                     ),
                 },
@@ -911,40 +909,7 @@
                 is_assoc: false,
             },
             FileSymbol {
-                name: "StructInModB",
-                def: Adt(
-                    Struct(
-                        Struct {
-                            id: StructId(
-                                4,
-                            ),
-                        },
-                    ),
-                ),
-                loc: DeclarationLocation {
-                    hir_file_id: EditionedFileId(
-                        FileId(
-                            1,
-                        ),
-                        Edition2021,
-                    ),
-                    ptr: SyntaxNodePtr {
-                        kind: STRUCT,
-                        range: 0..20,
-                    },
-                    name_ptr: AstPtr(
-                        SyntaxNodePtr {
-                            kind: NAME,
-                            range: 7..19,
-                        },
-                    ),
-                },
-                container_name: None,
-                is_alias: false,
-                is_assoc: false,
-            },
-            FileSymbol {
-                name: "SuperItemLikeMacro",
+                name: "IsThisJustATrait",
                 def: Macro(
                     Macro {
                         id: Macro2Id(
@@ -963,12 +928,12 @@
                     ),
                     ptr: SyntaxNodePtr {
                         kind: USE_TREE,
-                        range: 25..59,
+                        range: 141..173,
                     },
                     name_ptr: AstPtr(
                         SyntaxNodePtr {
                             kind: NAME,
-                            range: 41..59,
+                            range: 157..173,
                         },
                     ),
                 },
@@ -977,7 +942,7 @@
                 is_assoc: false,
             },
             FileSymbol {
-                name: "ThisStruct",
+                name: "StructInModB",
                 def: Adt(
                     Struct(
                         Struct {
@@ -995,13 +960,13 @@
                         Edition2021,
                     ),
                     ptr: SyntaxNodePtr {
-                        kind: USE_TREE,
-                        range: 65..105,
+                        kind: STRUCT,
+                        range: 0..20,
                     },
                     name_ptr: AstPtr(
                         SyntaxNodePtr {
                             kind: NAME,
-                            range: 95..105,
+                            range: 7..19,
                         },
                     ),
                 },
@@ -1010,15 +975,15 @@
                 is_assoc: false,
             },
             FileSymbol {
-                name: "ThisStruct",
-                def: Adt(
-                    Struct(
-                        Struct {
-                            id: StructId(
-                                4,
+                name: "SuperItemLikeMacro",
+                def: Macro(
+                    Macro {
+                        id: Macro2Id(
+                            Macro2Id(
+                                0,
                             ),
-                        },
-                    ),
+                        ),
+                    },
                 ),
                 loc: DeclarationLocation {
                     hir_file_id: EditionedFileId(
@@ -1029,12 +994,12 @@
                     ),
                     ptr: SyntaxNodePtr {
                         kind: USE_TREE,
-                        range: 65..105,
+                        range: 35..69,
                     },
                     name_ptr: AstPtr(
                         SyntaxNodePtr {
                             kind: NAME,
-                            range: 95..105,
+                            range: 51..69,
                         },
                     ),
                 },
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/traits.rs b/src/tools/rust-analyzer/crates/ide-db/src/traits.rs
index 82aca50d039..0f67496d098 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/traits.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/traits.rs
@@ -123,7 +123,9 @@ mod tests {
     use crate::RootDatabase;
 
     /// Creates analysis from a multi-file fixture, returns positions marked with $0.
-    pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
+    pub(crate) fn position(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    ) -> (RootDatabase, FilePosition) {
         let change_fixture = ChangeFixture::parse(ra_fixture);
         let mut database = RootDatabase::default();
         database.apply_change(change_fixture.change);
@@ -133,7 +135,7 @@ mod tests {
         (database, FilePosition { file_id, offset })
     }
 
-    fn check_trait(ra_fixture: &str, expect: Expect) {
+    fn check_trait(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
         let (db, position) = position(ra_fixture);
         let sema = Semantics::new(&db);
         let file = sema.parse(position.file_id);
@@ -147,7 +149,7 @@ mod tests {
         expect.assert_eq(&actual);
     }
 
-    fn check_missing_assoc(ra_fixture: &str, expect: Expect) {
+    fn check_missing_assoc(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
         let (db, position) = position(ra_fixture);
         let sema = Semantics::new(&db);
         let file = sema.parse(position.file_id);
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs
index 2b59c1a22f6..7d62daf716c 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs
@@ -604,4 +604,23 @@ fn bar() {
         "#,
         );
     }
+
+    #[test]
+    fn enum_variant_type_ns() {
+        check_diagnostics(
+            r#"
+enum KvnDeserializerErr<I> {
+    UnexpectedKeyword { found: I, expected: I },
+}
+
+fn foo() {
+    let _x: KvnDeserializerErr<()> =
+        KvnDeserializerErr::<()>::UnexpectedKeyword { found: (), expected: () };
+    let _x: KvnDeserializerErr<()> =
+        KvnDeserializerErr::<()>::UnexpectedKeyword::<()> { found: (), expected: () };
+                                                // ^^^^^^ 💡 error: you can specify generic arguments on either the enum or the variant, but not both
+}
+        "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
index 4c0c685e550..96a368eb0ea 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
@@ -41,7 +41,7 @@ pub(crate) fn inactive_code(
 mod tests {
     use crate::{tests::check_diagnostics_with_config, DiagnosticsConfig};
 
-    pub(crate) fn check(ra_fixture: &str) {
+    pub(crate) fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         let config = DiagnosticsConfig {
             disabled: std::iter::once("unlinked-file".to_owned()).collect(),
             ..DiagnosticsConfig::test_sample()
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
index e177b72e4d4..99894fefef3 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
@@ -4,13 +4,13 @@ use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, Severity};
 //
 // This diagnostic is shown for macro expansion errors.
 
-// Diagnostic: proc-macros-disabled
+// Diagnostic: attribute-expansion-disabled
 //
-// This diagnostic is shown for proc macros where proc macros have been disabled.
+// This diagnostic is shown for attribute proc macros when attribute expansions have been disabled.
 
 // Diagnostic: proc-macro-disabled
 //
-// This diagnostic is shown for proc macros that has been specifically disabled via `rust-analyzer.procMacro.ignored`.
+// This diagnostic is shown for proc macros that have been specifically disabled via `rust-analyzer.procMacro.ignored`.
 pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic {
     // Use more accurate position if available.
     let display_range = ctx.resolve_precise_location(&d.node, d.precise_location);
@@ -291,4 +291,30 @@ mod prim_never {}
 "#,
         );
     }
+
+    #[test]
+    fn no_stack_overflow_for_missing_binding() {
+        check_diagnostics(
+            r#"
+#[macro_export]
+macro_rules! boom {
+    (
+        $($code:literal),+,
+        $(param: $param:expr,)?
+    ) => {{
+        let _ = $crate::boom!(@param $($param)*);
+    }};
+    (@param) => { () };
+    (@param $param:expr) => { $param };
+}
+
+fn it_works() {
+    // NOTE: there is an error, but RA crashes before showing it
+    boom!("RAND", param: c7.clone());
+               // ^^^^^ error: expected literal
+}
+
+        "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
index 08e6e7dced9..0bf600e5dfa 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
@@ -26,7 +26,7 @@ mod tests {
     use test_utils::skip_slow_tests;
 
     #[track_caller]
-    fn check_diagnostics_no_bails(ra_fixture: &str) {
+    fn check_diagnostics_no_bails(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         cov_mark::check_count!(validate_match_bailed_out, 0);
         crate::tests::check_diagnostics(ra_fixture)
     }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
index e5d871975b6..0f126a1a656 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
@@ -399,4 +399,38 @@ fn f(s@m::Struct {
 "#,
         )
     }
+
+    #[test]
+    fn editions_between_macros() {
+        check_diagnostics(
+            r#"
+//- /edition2015.rs crate:edition2015 edition:2015
+#[macro_export]
+macro_rules! pass_expr_thorough {
+    ($e:expr) => { $e };
+}
+
+//- /edition2018.rs crate:edition2018 deps:edition2015 edition:2018
+async fn bar() {}
+async fn foo() {
+    edition2015::pass_expr_thorough!(bar().await);
+}
+        "#,
+        );
+        check_diagnostics(
+            r#"
+//- /edition2018.rs crate:edition2018 edition:2018
+pub async fn bar() {}
+#[macro_export]
+macro_rules! make_await {
+    () => { async { $crate::bar().await }; };
+}
+
+//- /edition2015.rs crate:edition2015 deps:edition2018 edition:2015
+fn foo() {
+    edition2018::make_await!();
+}
+        "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
index f481365f2a5..4aff446de60 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
@@ -61,7 +61,7 @@ mod tests {
     };
 
     #[track_caller]
-    pub(crate) fn check_diagnostics(ra_fixture: &str) {
+    pub(crate) fn check_diagnostics(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         let mut config = DiagnosticsConfig::test_sample();
         config.disabled.insert("inactive-code".to_owned());
         config.disabled.insert("E0599".to_owned());
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 bfdda537405..56afb38cc81 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
@@ -1164,6 +1164,37 @@ struct Bar {
     }
 
     #[test]
+    fn trait_upcast_ok() {
+        check_diagnostics(
+            r#"
+//- minicore: coerce_unsized
+trait A: B {}
+trait B {}
+
+fn test(a: &dyn A) -> &dyn B {
+    a
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn trait_upcast_err() {
+        check_diagnostics(
+            r#"
+//- minicore: coerce_unsized
+trait A {} // `A` does not have `B` as a supertrait, so no upcast :c
+trait B {}
+
+fn test(a: &dyn A) -> &dyn B {
+    a
+  //^ error: expected &dyn B, found &dyn A
+}
+"#,
+        );
+    }
+
+    #[test]
     fn return_no_value() {
         check_diagnostics_with_disabled(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs
index ec74640a54d..fc2a7db7174 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs
@@ -1,5 +1,7 @@
 #![allow(clippy::print_stderr)]
 
+mod overly_long_real_world_cases;
+
 use ide_db::{
     assists::AssistResolveStrategy, base_db::SourceDatabase, LineIndexDatabase, RootDatabase,
 };
@@ -16,7 +18,10 @@ use crate::{DiagnosticsConfig, ExprFillDefaultMode, Severity};
 ///  * the first diagnostic fix trigger range touches the input cursor position
 ///  * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied
 #[track_caller]
-pub(crate) fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) {
+pub(crate) fn check_fix(
+    #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
+) {
     check_nth_fix(0, ra_fixture_before, ra_fixture_after);
 }
 /// Takes a multi-file input fixture with annotated cursor positions,
@@ -24,14 +29,21 @@ pub(crate) fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) {
 ///  * a diagnostic is produced
 ///  * every diagnostic fixes trigger range touches the input cursor position
 ///  * that the contents of the file containing the cursor match `after` after each diagnostic fix is applied
-pub(crate) fn check_fixes(ra_fixture_before: &str, ra_fixtures_after: Vec<&str>) {
+pub(crate) fn check_fixes(
+    #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+    ra_fixtures_after: Vec<&str>,
+) {
     for (i, ra_fixture_after) in ra_fixtures_after.iter().enumerate() {
         check_nth_fix(i, ra_fixture_before, ra_fixture_after)
     }
 }
 
 #[track_caller]
-fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) {
+fn check_nth_fix(
+    nth: usize,
+    #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
+) {
     let mut config = DiagnosticsConfig::test_sample();
     config.expr_fill_default = ExprFillDefaultMode::Default;
     check_nth_fix_with_config(config, nth, ra_fixture_before, ra_fixture_after)
@@ -39,8 +51,8 @@ fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) {
 
 #[track_caller]
 pub(crate) fn check_fix_with_disabled(
-    ra_fixture_before: &str,
-    ra_fixture_after: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
     disabled: impl Iterator<Item = String>,
 ) {
     let mut config = DiagnosticsConfig::test_sample();
@@ -53,8 +65,8 @@ pub(crate) fn check_fix_with_disabled(
 fn check_nth_fix_with_config(
     config: DiagnosticsConfig,
     nth: usize,
-    ra_fixture_before: &str,
-    ra_fixture_after: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
 ) {
     let after = trim_indent(ra_fixture_after);
 
@@ -93,14 +105,20 @@ fn check_nth_fix_with_config(
     assert_eq_text!(&after, &actual);
 }
 
-pub(crate) fn check_fixes_unordered(ra_fixture_before: &str, ra_fixtures_after: Vec<&str>) {
+pub(crate) fn check_fixes_unordered(
+    #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+    ra_fixtures_after: Vec<&str>,
+) {
     for ra_fixture_after in ra_fixtures_after.iter() {
         check_has_fix(ra_fixture_before, ra_fixture_after)
     }
 }
 
 #[track_caller]
-pub(crate) fn check_has_fix(ra_fixture_before: &str, ra_fixture_after: &str) {
+pub(crate) fn check_has_fix(
+    #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
+) {
     let after = trim_indent(ra_fixture_after);
 
     let (db, file_position) = RootDatabase::with_position(ra_fixture_before);
@@ -143,7 +161,10 @@ pub(crate) fn check_has_fix(ra_fixture_before: &str, ra_fixture_after: &str) {
 }
 
 #[track_caller]
-pub(crate) fn check_has_single_fix(ra_fixture_before: &str, ra_fixture_after: &str) {
+pub(crate) fn check_has_single_fix(
+    #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
+) {
     let after = trim_indent(ra_fixture_after);
 
     let (db, file_position) = RootDatabase::with_position(ra_fixture_before);
@@ -189,7 +210,7 @@ pub(crate) fn check_has_single_fix(ra_fixture_before: &str, ra_fixture_after: &s
 }
 
 /// Checks that there's a diagnostic *without* fix at `$0`.
-pub(crate) fn check_no_fix(ra_fixture: &str) {
+pub(crate) fn check_no_fix(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
     let (db, file_position) = RootDatabase::with_position(ra_fixture);
     let diagnostic = super::full_diagnostics(
         &db,
@@ -203,21 +224,27 @@ pub(crate) fn check_no_fix(ra_fixture: &str) {
 }
 
 #[track_caller]
-pub(crate) fn check_diagnostics(ra_fixture: &str) {
+pub(crate) fn check_diagnostics(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
     let mut config = DiagnosticsConfig::test_sample();
     config.disabled.insert("inactive-code".to_owned());
     check_diagnostics_with_config(config, ra_fixture)
 }
 
 #[track_caller]
-pub(crate) fn check_diagnostics_with_disabled(ra_fixture: &str, disabled: &[&str]) {
+pub(crate) fn check_diagnostics_with_disabled(
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    disabled: &[&str],
+) {
     let mut config = DiagnosticsConfig::test_sample();
     config.disabled.extend(disabled.iter().map(|&s| s.to_owned()));
     check_diagnostics_with_config(config, ra_fixture)
 }
 
 #[track_caller]
-pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixture: &str) {
+pub(crate) fn check_diagnostics_with_config(
+    config: DiagnosticsConfig,
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+) {
     let (db, files) = RootDatabase::with_many_files(ra_fixture);
     let mut annotations = files
         .iter()
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests/overly_long_real_world_cases.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests/overly_long_real_world_cases.rs
new file mode 100644
index 00000000000..c6831d818aa
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests/overly_long_real_world_cases.rs
@@ -0,0 +1,2726 @@
+//! Overly long excerpts of failures from real world cases, that I was too lazy to minimize.
+
+use crate::tests::check_diagnostics_with_disabled;
+
+#[test]
+fn tracing_infinite_repeat() {
+    check_diagnostics_with_disabled(
+        r#"
+//- /core.rs crate:core
+#[rustc_builtin_macro]
+#[macro_export]
+macro_rules! concat {
+($($e:expr),* $(,)?) => {{ /* compiler built-in */ }};
+}
+#[rustc_builtin_macro]
+#[macro_export]
+macro_rules! file {
+() => {
+    /* compiler built-in */
+};
+}
+#[allow_internal_unsafe]
+#[allow_internal_unstable(fmt_internals)]
+#[rustc_builtin_macro]
+#[macro_export]
+macro_rules! format_args {
+($fmt:expr) => {{ /* compiler built-in */ }};
+($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }};
+}
+#[rustc_builtin_macro]
+#[macro_export]
+macro_rules! line {
+() => {
+    /* compiler built-in */
+};
+}
+
+//- /tracing_core.rs crate:tracing_core deps:core
+#[macro_export]
+macro_rules! identify_callsite {
+($callsite:expr) => {
+    $crate::callsite::Identifier($callsite)
+};
+}
+
+#[macro_export]
+macro_rules! metadata {
+(
+    name: $name:expr,
+    target: $target:expr,
+    level: $level:expr,
+    fields: $fields:expr,
+    callsite: $callsite:expr,
+    kind: $kind:expr
+) => {
+    $crate::metadata! {
+        name: $name,
+        target: $target,
+        level: $level,
+        fields: $fields,
+        callsite: $callsite,
+        kind: $kind,
+    }
+};
+(
+    name: $name:expr,
+    target: $target:expr,
+    level: $level:expr,
+    fields: $fields:expr,
+    callsite: $callsite:expr,
+    kind: $kind:expr,
+) => {
+    $crate::metadata::Metadata::new(
+        $name,
+        $target,
+        $level,
+        $crate::__macro_support::Option::Some($crate::__macro_support::file!()),
+        $crate::__macro_support::Option::Some($crate::__macro_support::line!()),
+        $crate::__macro_support::Option::Some($crate::__macro_support::module_path!()),
+        $crate::field::FieldSet::new($fields, $crate::identify_callsite!($callsite)),
+        $kind,
+    )
+};
+}
+
+//- /tracing.rs crate:tracing deps:core,tracing_core
+#[doc(hidden)]
+pub mod __macro_support {
+// Re-export the `core` functions that are used in macros. This allows
+// a crate to be named `core` and avoid name clashes.
+// See here: https://github.com/tokio-rs/tracing/issues/2761
+pub use core::{concat, file, format_args, iter::Iterator, line, option::Option};
+}
+
+#[macro_export]
+macro_rules! span {
+(target: $target:expr, parent: $parent:expr, $lvl:expr, $name:expr) => {
+    $crate::span!(target: $target, parent: $parent, $lvl, $name,)
+};
+(target: $target:expr, parent: $parent:expr, $lvl:expr, $name:expr, $($fields:tt)*) => {
+    {
+        use $crate::__macro_support::Callsite as _;
+        static __CALLSITE: $crate::__macro_support::MacroCallsite = $crate::callsite2! {
+            name: $name,
+            kind: $crate::metadata::Kind::SPAN,
+            target: $target,
+            level: $lvl,
+            fields: $($fields)*
+        };
+        let mut interest = $crate::subscriber::Interest::never();
+        if $crate::level_enabled!($lvl)
+            && { interest = __CALLSITE.interest(); !interest.is_never() }
+            && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest)
+        {
+            let meta = __CALLSITE.metadata();
+            // span with explicit parent
+            $crate::Span::child_of(
+                $parent,
+                meta,
+                &$crate::valueset!(meta.fields(), $($fields)*),
+            )
+        } else {
+            let span = $crate::__macro_support::__disabled_span(__CALLSITE.metadata());
+            $crate::if_log_enabled! { $lvl, {
+                span.record_all(&$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*));
+            }};
+            span
+        }
+    }
+};
+(target: $target:expr, $lvl:expr, $name:expr, $($fields:tt)*) => {
+    {
+        use $crate::__macro_support::Callsite as _;
+        static __CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! {
+            name: $name,
+            kind: $crate::metadata::Kind::SPAN,
+            target: $target,
+            level: $lvl,
+            fields: $($fields)*
+        };
+        let mut interest = $crate::subscriber::Interest::never();
+        if $crate::level_enabled!($lvl)
+            && { interest = __CALLSITE.interest(); !interest.is_never() }
+            && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest)
+        {
+            let meta = __CALLSITE.metadata();
+            // span with contextual parent
+            $crate::Span::new(
+                meta,
+                &$crate::valueset!(meta.fields(), $($fields)*),
+            )
+        } else {
+            let span = $crate::__macro_support::__disabled_span(__CALLSITE.metadata());
+            $crate::if_log_enabled! { $lvl, {
+                span.record_all(&$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*));
+            }};
+            span
+        }
+    }
+};
+(target: $target:expr, parent: $parent:expr, $lvl:expr, $name:expr) => {
+    $crate::span!(target: $target, parent: $parent, $lvl, $name,)
+};
+(parent: $parent:expr, $lvl:expr, $name:expr, $($fields:tt)*) => {
+    $crate::span!(
+        target: module_path!(),
+        parent: $parent,
+        $lvl,
+        $name,
+        $($fields)*
+    )
+};
+(parent: $parent:expr, $lvl:expr, $name:expr) => {
+    $crate::span!(
+        target: module_path!(),
+        parent: $parent,
+        $lvl,
+        $name,
+    )
+};
+(target: $target:expr, $lvl:expr, $name:expr, $($fields:tt)*) => {
+    $crate::span!(
+        target: $target,
+        $lvl,
+        $name,
+        $($fields)*
+    )
+};
+(target: $target:expr, $lvl:expr, $name:expr) => {
+    $crate::span!(target: $target, $lvl, $name,)
+};
+($lvl:expr, $name:expr, $($fields:tt)*) => {
+    $crate::span!(
+        target: module_path!(),
+        $lvl,
+        $name,
+        $($fields)*
+    )
+};
+($lvl:expr, $name:expr) => {
+    $crate::span!(
+        target: module_path!(),
+        $lvl,
+        $name,
+    )
+};
+}
+
+#[macro_export]
+macro_rules! trace_span {
+(target: $target:expr, parent: $parent:expr, $name:expr, $($field:tt)*) => {
+    $crate::span!(
+        target: $target,
+        parent: $parent,
+        $crate::Level::TRACE,
+        $name,
+        $($field)*
+    )
+};
+(target: $target:expr, parent: $parent:expr, $name:expr) => {
+    $crate::trace_span!(target: $target, parent: $parent, $name,)
+};
+(parent: $parent:expr, $name:expr, $($field:tt)*) => {
+    $crate::span!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::TRACE,
+        $name,
+        $($field)*
+    )
+};
+(parent: $parent:expr, $name:expr) => {
+    $crate::trace_span!(parent: $parent, $name,)
+};
+(target: $target:expr, $name:expr, $($field:tt)*) => {
+    $crate::span!(
+        target: $target,
+        $crate::Level::TRACE,
+        $name,
+        $($field)*
+    )
+};
+(target: $target:expr, $name:expr) => {
+    $crate::trace_span!(target: $target, $name,)
+};
+($name:expr, $($field:tt)*) => {
+    $crate::span!(
+        target: module_path!(),
+        $crate::Level::TRACE,
+        $name,
+        $($field)*
+    )
+};
+($name:expr) => { $crate::trace_span!($name,) };
+}
+
+#[macro_export]
+macro_rules! debug_span {
+(target: $target:expr, parent: $parent:expr, $name:expr, $($field:tt)*) => {
+    $crate::span!(
+        target: $target,
+        parent: $parent,
+        $crate::Level::DEBUG,
+        $name,
+        $($field)*
+    )
+};
+(target: $target:expr, parent: $parent:expr, $name:expr) => {
+    $crate::debug_span!(target: $target, parent: $parent, $name,)
+};
+(parent: $parent:expr, $name:expr, $($field:tt)*) => {
+    $crate::span!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::DEBUG,
+        $name,
+        $($field)*
+    )
+};
+(parent: $parent:expr, $name:expr) => {
+    $crate::debug_span!(parent: $parent, $name,)
+};
+(target: $target:expr, $name:expr, $($field:tt)*) => {
+    $crate::span!(
+        target: $target,
+        $crate::Level::DEBUG,
+        $name,
+        $($field)*
+    )
+};
+(target: $target:expr, $name:expr) => {
+    $crate::debug_span!(target: $target, $name,)
+};
+($name:expr, $($field:tt)*) => {
+    $crate::span!(
+        target: module_path!(),
+        $crate::Level::DEBUG,
+        $name,
+        $($field)*
+    )
+};
+($name:expr) => {$crate::debug_span!($name,)};
+}
+
+#[macro_export]
+macro_rules! info_span {
+(target: $target:expr, parent: $parent:expr, $name:expr, $($field:tt)*) => {
+    $crate::span!(
+        target: $target,
+        parent: $parent,
+        $crate::Level::INFO,
+        $name,
+        $($field)*
+    )
+};
+(target: $target:expr, parent: $parent:expr, $name:expr) => {
+    $crate::info_span!(target: $target, parent: $parent, $name,)
+};
+(parent: $parent:expr, $name:expr, $($field:tt)*) => {
+    $crate::span!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::INFO,
+        $name,
+        $($field)*
+    )
+};
+(parent: $parent:expr, $name:expr) => {
+    $crate::info_span!(parent: $parent, $name,)
+};
+(target: $target:expr, $name:expr, $($field:tt)*) => {
+    $crate::span!(
+        target: $target,
+        $crate::Level::INFO,
+        $name,
+        $($field)*
+    )
+};
+(target: $target:expr, $name:expr) => {
+    $crate::info_span!(target: $target, $name,)
+};
+($name:expr, $($field:tt)*) => {
+    $crate::span!(
+        target: module_path!(),
+        $crate::Level::INFO,
+        $name,
+        $($field)*
+    )
+};
+($name:expr) => {$crate::info_span!($name,)};
+}
+
+#[macro_export]
+macro_rules! warn_span {
+(target: $target:expr, parent: $parent:expr, $name:expr, $($field:tt)*) => {
+    $crate::span!(
+        target: $target,
+        parent: $parent,
+        $crate::Level::WARN,
+        $name,
+        $($field)*
+    )
+};
+(target: $target:expr, parent: $parent:expr, $name:expr) => {
+    $crate::warn_span!(target: $target, parent: $parent, $name,)
+};
+(parent: $parent:expr, $name:expr, $($field:tt)*) => {
+    $crate::span!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::WARN,
+        $name,
+        $($field)*
+    )
+};
+(parent: $parent:expr, $name:expr) => {
+    $crate::warn_span!(parent: $parent, $name,)
+};
+(target: $target:expr, $name:expr, $($field:tt)*) => {
+    $crate::span!(
+        target: $target,
+        $crate::Level::WARN,
+        $name,
+        $($field)*
+    )
+};
+(target: $target:expr, $name:expr) => {
+    $crate::warn_span!(target: $target, $name,)
+};
+($name:expr, $($field:tt)*) => {
+    $crate::span!(
+        target: module_path!(),
+        $crate::Level::WARN,
+        $name,
+        $($field)*
+    )
+};
+($name:expr) => {$crate::warn_span!($name,)};
+}
+
+#[macro_export]
+macro_rules! error_span {
+(target: $target:expr, parent: $parent:expr, $name:expr, $($field:tt)*) => {
+    $crate::span!(
+        target: $target,
+        parent: $parent,
+        $crate::Level::ERROR,
+        $name,
+        $($field)*
+    )
+};
+(target: $target:expr, parent: $parent:expr, $name:expr) => {
+    $crate::error_span!(target: $target, parent: $parent, $name,)
+};
+(parent: $parent:expr, $name:expr, $($field:tt)*) => {
+    $crate::span!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::ERROR,
+        $name,
+        $($field)*
+    )
+};
+(parent: $parent:expr, $name:expr) => {
+    $crate::error_span!(parent: $parent, $name,)
+};
+(target: $target:expr, $name:expr, $($field:tt)*) => {
+    $crate::span!(
+        target: $target,
+        $crate::Level::ERROR,
+        $name,
+        $($field)*
+    )
+};
+(target: $target:expr, $name:expr) => {
+    $crate::error_span!(target: $target, $name,)
+};
+($name:expr, $($field:tt)*) => {
+    $crate::span!(
+        target: module_path!(),
+        $crate::Level::ERROR,
+        $name,
+        $($field)*
+    )
+};
+($name:expr) => {$crate::error_span!($name,)};
+}
+
+#[macro_export]
+macro_rules! event {
+// Name / target / parent.
+(name: $name:expr, target: $target:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* } )=> ({
+    use $crate::__macro_support::Callsite as _;
+    static __CALLSITE: $crate::__macro_support::MacroCallsite = $crate::callsite2! {
+        name: $name,
+        kind: $crate::metadata::Kind::EVENT,
+        target: $target,
+        level: $lvl,
+        fields: $($fields)*
+    };
+
+    let enabled = $crate::level_enabled!($lvl) && {
+        let interest = __CALLSITE.interest();
+        !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest)
+    };
+    if enabled {
+        (|value_set: $crate::field::ValueSet| {
+            $crate::__tracing_log!(
+                $lvl,
+                __CALLSITE,
+                &value_set
+            );
+            let meta = __CALLSITE.metadata();
+            // event with explicit parent
+            $crate::Event::child_of(
+                $parent,
+                meta,
+                &value_set
+            );
+        })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*));
+    } else {
+        $crate::__tracing_log!(
+            $lvl,
+            __CALLSITE,
+            &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)
+        );
+    }
+});
+(name: $name:expr, target: $target:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
+    $crate::event!(
+        name: $name,
+        target: $target,
+        parent: $parent,
+        $lvl,
+        { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* }
+    )
+);
+(name: $name:expr, target: $target:expr, parent: $parent:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $lvl, { $($k).+ = $($fields)* })
+);
+(name: $name:expr, target: $target:expr, parent: $parent:expr, $lvl:expr, $($arg:tt)+) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $lvl, { $($arg)+ })
+);
+
+// Name / target.
+(name: $name:expr, target: $target:expr, $lvl:expr, { $($fields:tt)* } )=> ({
+    use $crate::__macro_support::Callsite as _;
+    static __CALLSITE: $crate::__macro_support::MacroCallsite = $crate::callsite2! {
+        name: $name,
+        kind: $crate::metadata::Kind::EVENT,
+        target: $target,
+        level: $lvl,
+        fields: $($fields)*
+    };
+    let enabled = $crate::level_enabled!($lvl) && {
+        let interest = __CALLSITE.interest();
+        !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest)
+    };
+    if enabled {
+        (|value_set: $crate::field::ValueSet| {
+            let meta = __CALLSITE.metadata();
+            // event with contextual parent
+            $crate::Event::dispatch(
+                meta,
+                &value_set
+            );
+            $crate::__tracing_log!(
+                $lvl,
+                __CALLSITE,
+                &value_set
+            );
+        })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*));
+    } else {
+        $crate::__tracing_log!(
+            $lvl,
+            __CALLSITE,
+            &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)
+        );
+    }
+});
+(name: $name:expr, target: $target:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
+    $crate::event!(
+        name: $name,
+        target: $target,
+        $lvl,
+        { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* }
+    )
+);
+(name: $name:expr, target: $target:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => (
+    $crate::event!(name: $name, target: $target, $lvl, { $($k).+ = $($fields)* })
+);
+(name: $name:expr, target: $target:expr, $lvl:expr, $($arg:tt)+) => (
+    $crate::event!(name: $name, target: $target, $lvl, { $($arg)+ })
+);
+
+// Target / parent.
+(target: $target:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* } )=> ({
+    use $crate::__macro_support::Callsite as _;
+    static __CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! {
+        name: $crate::__macro_support::concat!(
+            "event ",
+            $crate::__macro_support::file!(),
+            ":",
+            $crate::__macro_support::line!()
+        ),
+        kind: $crate::metadata::Kind::EVENT,
+        target: $target,
+        level: $lvl,
+        fields: $($fields)*
+    };
+
+    let enabled = $crate::level_enabled!($lvl) && {
+        let interest = __CALLSITE.interest();
+        !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest)
+    };
+    if enabled {
+        (|value_set: $crate::field::ValueSet| {
+            $crate::__tracing_log!(
+                $lvl,
+                __CALLSITE,
+                &value_set
+            );
+            let meta = __CALLSITE.metadata();
+            // event with explicit parent
+            $crate::Event::child_of(
+                $parent,
+                meta,
+                &value_set
+            );
+        })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*));
+    } else {
+        $crate::__tracing_log!(
+            $lvl,
+            __CALLSITE,
+            &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)
+        );
+    }
+});
+(target: $target:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
+    $crate::event!(
+        target: $target,
+        parent: $parent,
+        $lvl,
+        { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* }
+    )
+);
+(target: $target:expr, parent: $parent:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => (
+    $crate::event!(target: $target, parent: $parent, $lvl, { $($k).+ = $($fields)* })
+);
+(target: $target:expr, parent: $parent:expr, $lvl:expr, $($arg:tt)+) => (
+    $crate::event!(target: $target, parent: $parent, $lvl, { $($arg)+ })
+);
+
+// Name / parent.
+(name: $name:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* } )=> ({
+    use $crate::__macro_support::Callsite as _;
+    static __CALLSITE: $crate::__macro_support::MacroCallsite = $crate::callsite2! {
+        name: $name,
+        kind: $crate::metadata::Kind::EVENT,
+        target: module_path!(),
+        level: $lvl,
+        fields: $($fields)*
+    };
+
+    let enabled = $crate::level_enabled!($lvl) && {
+        let interest = __CALLSITE.interest();
+        !interest.is_never() && __CALLSITE.is_enabled(interest)
+    };
+    if enabled {
+        (|value_set: $crate::field::ValueSet| {
+            $crate::__tracing_log!(
+                $lvl,
+                __CALLSITE,
+                &value_set
+            );
+            let meta = __CALLSITE.metadata();
+            // event with explicit parent
+            $crate::Event::child_of(
+                $parent,
+                meta,
+                &value_set
+            );
+        })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*));
+    } else {
+        $crate::__tracing_log!(
+            $lvl,
+            __CALLSITE,
+            &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)
+        );
+    }
+});
+(name: $name:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
+    $crate::event!(
+        name: $name,
+        parent: $parent,
+        $lvl,
+        { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* }
+    )
+);
+(name: $name:expr, parent: $parent:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => (
+    $crate::event!(name: $name, parent: $parent, $lvl, { $($k).+ = $($fields)* })
+);
+(name: $name:expr, parent: $parent:expr, $lvl:expr, $($arg:tt)+) => (
+    $crate::event!(name: $name, parent: $parent, $lvl, { $($arg)+ })
+);
+
+// Name.
+(name: $name:expr, $lvl:expr, { $($fields:tt)* } )=> ({
+    use $crate::__macro_support::Callsite as _;
+    static __CALLSITE: $crate::__macro_support::MacroCallsite = $crate::callsite2! {
+        name: $name,
+        kind: $crate::metadata::Kind::EVENT,
+        target: module_path!(),
+        level: $lvl,
+        fields: $($fields)*
+    };
+    let enabled = $crate::level_enabled!($lvl) && {
+        let interest = __CALLSITE.interest();
+        !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest)
+    };
+    if enabled {
+        (|value_set: $crate::field::ValueSet| {
+            let meta = __CALLSITE.metadata();
+            // event with contextual parent
+            $crate::Event::dispatch(
+                meta,
+                &value_set
+            );
+            $crate::__tracing_log!(
+                $lvl,
+                __CALLSITE,
+                &value_set
+            );
+        })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*));
+    } else {
+        $crate::__tracing_log!(
+            $lvl,
+            __CALLSITE,
+            &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)
+        );
+    }
+});
+(name: $name:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
+    $crate::event!(
+        name: $name,
+        $lvl,
+        { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* }
+    )
+);
+(name: $name:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => (
+    $crate::event!(name: $name, $lvl, { $($k).+ = $($fields)* })
+);
+(name: $name:expr, $lvl:expr, $($arg:tt)+ ) => (
+    $crate::event!(name: $name, $lvl, { $($arg)+ })
+);
+
+// Target.
+(target: $target:expr, $lvl:expr, { $($fields:tt)* } )=> ({
+    use $crate::__macro_support::Callsite as _;
+    static __CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! {
+        name: $crate::__macro_support::concat!(
+            "event ",
+            $crate::__macro_support::file!(),
+            ":",
+            $crate::__macro_support::line!()
+        ),
+        kind: $crate::metadata::Kind::EVENT,
+        target: $target,
+        level: $lvl,
+        fields: $($fields)*
+    };
+    let enabled = $crate::level_enabled!($lvl) && {
+        let interest = __CALLSITE.interest();
+        !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest)
+    };
+    if enabled {
+        (|value_set: $crate::field::ValueSet| {
+            let meta = __CALLSITE.metadata();
+            // event with contextual parent
+            $crate::Event::dispatch(
+                meta,
+                &value_set
+            );
+            $crate::__tracing_log!(
+                $lvl,
+                __CALLSITE,
+                &value_set
+            );
+        })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*));
+    } else {
+        $crate::__tracing_log!(
+            $lvl,
+            __CALLSITE,
+            &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)
+        );
+    }
+});
+(target: $target:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
+    $crate::event!(
+        target: $target,
+        $lvl,
+        { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* }
+    )
+);
+(target: $target:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => (
+    $crate::event!(target: $target, $lvl, { $($k).+ = $($fields)* })
+);
+(target: $target:expr, $lvl:expr, $($arg:tt)+ ) => (
+    $crate::event!(target: $target, $lvl, { $($arg)+ })
+);
+
+// Parent.
+(parent: $parent:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $lvl,
+        { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* }
+    )
+);
+(parent: $parent:expr, $lvl:expr, $($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $lvl,
+        { $($k).+ = $($field)*}
+    )
+);
+(parent: $parent:expr, $lvl:expr, ?$($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $lvl,
+        { ?$($k).+ = $($field)*}
+    )
+);
+(parent: $parent:expr, $lvl:expr, %$($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $lvl,
+        { %$($k).+ = $($field)*}
+    )
+);
+(parent: $parent:expr, $lvl:expr, $($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $lvl,
+        { $($k).+, $($field)*}
+    )
+);
+(parent: $parent:expr, $lvl:expr, %$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $lvl,
+        { %$($k).+, $($field)*}
+    )
+);
+(parent: $parent:expr, $lvl:expr, ?$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $lvl,
+        { ?$($k).+, $($field)*}
+    )
+);
+(parent: $parent:expr, $lvl:expr, $($arg:tt)+ ) => (
+    $crate::event!(target: module_path!(), parent: $parent, $lvl, { $($arg)+ })
+);
+
+// ...
+( $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
+    $crate::event!(
+        target: module_path!(),
+        $lvl,
+        { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* }
+    )
+);
+( $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
+    $crate::event!(
+        target: module_path!(),
+        $lvl,
+        { message = format_args!($($arg)+), $($fields)* }
+    )
+);
+($lvl:expr, $($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $lvl,
+        { $($k).+ = $($field)*}
+    )
+);
+($lvl:expr, $($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $lvl,
+        { $($k).+, $($field)*}
+    )
+);
+($lvl:expr, ?$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $lvl,
+        { ?$($k).+, $($field)*}
+    )
+);
+($lvl:expr, %$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $lvl,
+        { %$($k).+, $($field)*}
+    )
+);
+($lvl:expr, ?$($k:ident).+) => (
+    $crate::event!($lvl, ?$($k).+,)
+);
+($lvl:expr, %$($k:ident).+) => (
+    $crate::event!($lvl, %$($k).+,)
+);
+($lvl:expr, $($k:ident).+) => (
+    $crate::event!($lvl, $($k).+,)
+);
+( $lvl:expr, $($arg:tt)+ ) => (
+    $crate::event!(target: module_path!(), $lvl, { $($arg)+ })
+);
+}
+
+#[macro_export]
+macro_rules! event_enabled {
+($($rest:tt)*)=> (
+    $crate::enabled!(kind: $crate::metadata::Kind::EVENT, $($rest)*)
+)
+}
+
+#[macro_export]
+macro_rules! span_enabled {
+($($rest:tt)*)=> (
+    $crate::enabled!(kind: $crate::metadata::Kind::SPAN, $($rest)*)
+)
+}
+
+#[macro_export]
+macro_rules! enabled {
+(kind: $kind:expr, target: $target:expr, $lvl:expr, { $($fields:tt)* } )=> ({
+    if $crate::level_enabled!($lvl) {
+        use $crate::__macro_support::Callsite as _;
+        static __CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! {
+            name: $crate::__macro_support::concat!(
+                "enabled ",
+                $crate::__macro_support::file!(),
+                ":",
+                $crate::__macro_support::line!()
+            ),
+            kind: $kind.hint(),
+            target: $target,
+            level: $lvl,
+            fields: $($fields)*
+        };
+        let interest = __CALLSITE.interest();
+        if !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest) {
+            let meta = __CALLSITE.metadata();
+            $crate::dispatcher::get_default(|current| current.enabled(meta))
+        } else {
+            false
+        }
+    } else {
+        false
+    }
+});
+// Just target and level
+(kind: $kind:expr, target: $target:expr, $lvl:expr ) => (
+    $crate::enabled!(kind: $kind, target: $target, $lvl, { })
+);
+(target: $target:expr, $lvl:expr ) => (
+    $crate::enabled!(kind: $crate::metadata::Kind::HINT, target: $target, $lvl, { })
+);
+
+// These four cases handle fields with no values
+(kind: $kind:expr, target: $target:expr, $lvl:expr, $($field:tt)*) => (
+    $crate::enabled!(
+        kind: $kind,
+        target: $target,
+        $lvl,
+        { $($field)*}
+    )
+);
+(target: $target:expr, $lvl:expr, $($field:tt)*) => (
+    $crate::enabled!(
+        kind: $crate::metadata::Kind::HINT,
+        target: $target,
+        $lvl,
+        { $($field)*}
+    )
+);
+
+// Level and field case
+(kind: $kind:expr, $lvl:expr, $($field:tt)*) => (
+    $crate::enabled!(
+        kind: $kind,
+        target: module_path!(),
+        $lvl,
+        { $($field)*}
+    )
+);
+
+// Simplest `enabled!` case
+(kind: $kind:expr, $lvl:expr) => (
+    $crate::enabled!(kind: $kind, target: module_path!(), $lvl, { })
+);
+($lvl:expr) => (
+    $crate::enabled!(kind: $crate::metadata::Kind::HINT, target: module_path!(), $lvl, { })
+);
+
+// Fallthrough from above
+($lvl:expr, $($field:tt)*) => (
+    $crate::enabled!(
+        kind: $crate::metadata::Kind::HINT,
+        target: module_path!(),
+        $lvl,
+        { $($field)*}
+    )
+);
+}
+
+#[macro_export]
+macro_rules! trace {
+// Name / target / parent.
+(name: $name:expr, target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { $($field)* }, $($arg)*)
+);
+(name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { ?$($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { %$($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, {}, $($arg)+)
+);
+
+// Name / target.
+(name: $name:expr, target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { $($field)* }, $($arg)*)
+);
+(name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { $($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { ?$($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { %$($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, $($arg:tt)+ ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::TRACE, {}, $($arg)+)
+);
+
+// Target / parent.
+(target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { $($field)* }, $($arg)*)
+);
+(target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)* })
+);
+(target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { ?$($k).+ $($field)* })
+);
+(target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { %$($k).+ $($field)* })
+);
+(target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, {}, $($arg)+)
+);
+
+// Name / parent.
+(name: $name:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { $($field)* }, $($arg)*)
+);
+(name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)* })
+);
+(name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { ?$($k).+ $($field)* })
+);
+(name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { %$($k).+ $($field)* })
+);
+(name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, {}, $($arg)+)
+);
+
+// Name.
+(name: $name:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(name: $name, $crate::Level::TRACE, { $($field)* }, $($arg)*)
+);
+(name: $name:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, $crate::Level::TRACE, { $($k).+ $($field)* })
+);
+(name: $name:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, $crate::Level::TRACE, { ?$($k).+ $($field)* })
+);
+(name: $name:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, $crate::Level::TRACE, { %$($k).+ $($field)* })
+);
+(name: $name:expr, $($arg:tt)+ ) => (
+    $crate::event!(name: $name, $crate::Level::TRACE, {}, $($arg)+)
+);
+
+// Target.
+(target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(target: $target, $crate::Level::TRACE, { $($field)* }, $($arg)*)
+);
+(target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, $crate::Level::TRACE, { $($k).+ $($field)* })
+);
+(target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, $crate::Level::TRACE, { ?$($k).+ $($field)* })
+);
+(target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, $crate::Level::TRACE, { %$($k).+ $($field)* })
+);
+(target: $target:expr, $($arg:tt)+ ) => (
+    $crate::event!(target: $target, $crate::Level::TRACE, {}, $($arg)+)
+);
+
+// Parent.
+(parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::TRACE,
+        { $($field)+ },
+        $($arg)+
+    )
+);
+(parent: $parent:expr, $($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::TRACE,
+        { $($k).+ = $($field)*}
+    )
+);
+(parent: $parent:expr, ?$($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::TRACE,
+        { ?$($k).+ = $($field)*}
+    )
+);
+(parent: $parent:expr, %$($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::TRACE,
+        { %$($k).+ = $($field)*}
+    )
+);
+(parent: $parent:expr, $($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::TRACE,
+        { $($k).+, $($field)*}
+    )
+);
+(parent: $parent:expr, ?$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::TRACE,
+        { ?$($k).+, $($field)*}
+    )
+);
+(parent: $parent:expr, %$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::TRACE,
+        { %$($k).+, $($field)*}
+    )
+);
+(parent: $parent:expr, $($arg:tt)+) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::TRACE,
+        {},
+        $($arg)+
+    )
+);
+
+// ...
+({ $($field:tt)+ }, $($arg:tt)+ ) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::TRACE,
+        { $($field)+ },
+        $($arg)+
+    )
+);
+($($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::TRACE,
+        { $($k).+ = $($field)*}
+    )
+);
+(?$($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::TRACE,
+        { ?$($k).+ = $($field)*}
+    )
+);
+(%$($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::TRACE,
+        { %$($k).+ = $($field)*}
+    )
+);
+($($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::TRACE,
+        { $($k).+, $($field)*}
+    )
+);
+(?$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::TRACE,
+        { ?$($k).+, $($field)*}
+    )
+);
+(%$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::TRACE,
+        { %$($k).+, $($field)*}
+    )
+);
+(?$($k:ident).+) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::TRACE,
+        { ?$($k).+ }
+    )
+);
+(%$($k:ident).+) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::TRACE,
+        { %$($k).+ }
+    )
+);
+($($k:ident).+) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::TRACE,
+        { $($k).+ }
+    )
+);
+($($arg:tt)+) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::TRACE,
+        $($arg)+
+    )
+);
+}
+
+#[macro_export]
+macro_rules! debug {
+// Name / target / parent.
+(name: $name:expr, target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
+);
+(name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+)
+);
+
+// Name / target.
+(name: $name:expr, target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
+);
+(name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { $($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { %$($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, $($arg:tt)+ ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, {}, $($arg)+)
+);
+
+// Target / parent.
+(target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
+);
+(target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)* })
+);
+(target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
+);
+(target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)* })
+);
+(target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+)
+);
+
+// Name / parent.
+(name: $name:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
+);
+(name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)* })
+);
+(name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
+);
+(name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)* })
+);
+(name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+)
+);
+
+// Name.
+(name: $name:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(name: $name, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
+);
+(name: $name:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, $crate::Level::DEBUG, { $($k).+ $($field)* })
+);
+(name: $name:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
+);
+(name: $name:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, $crate::Level::DEBUG, { %$($k).+ $($field)* })
+);
+(name: $name:expr, $($arg:tt)+ ) => (
+    $crate::event!(name: $name, $crate::Level::DEBUG, {}, $($arg)+)
+);
+
+// Target.
+(target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(target: $target, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
+);
+(target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, $crate::Level::DEBUG, { $($k).+ $($field)* })
+);
+(target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
+);
+(target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, $crate::Level::DEBUG, { %$($k).+ $($field)* })
+);
+(target: $target:expr, $($arg:tt)+ ) => (
+    $crate::event!(target: $target, $crate::Level::DEBUG, {}, $($arg)+)
+);
+
+// Parent.
+(parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::DEBUG,
+        { $($field)+ },
+        $($arg)+
+    )
+);
+(parent: $parent:expr, $($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::DEBUG,
+        { $($k).+ = $($field)*}
+    )
+);
+(parent: $parent:expr, ?$($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::DEBUG,
+        { ?$($k).+ = $($field)*}
+    )
+);
+(parent: $parent:expr, %$($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::DEBUG,
+        { %$($k).+ = $($field)*}
+    )
+);
+(parent: $parent:expr, $($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::DEBUG,
+        { $($k).+, $($field)*}
+    )
+);
+(parent: $parent:expr, ?$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::DEBUG,
+        { ?$($k).+, $($field)*}
+    )
+);
+(parent: $parent:expr, %$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::DEBUG,
+        { %$($k).+, $($field)*}
+    )
+);
+(parent: $parent:expr, $($arg:tt)+) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::DEBUG,
+        {},
+        $($arg)+
+    )
+);
+
+// ...
+({ $($field:tt)+ }, $($arg:tt)+ ) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::DEBUG,
+        { $($field)+ },
+        $($arg)+
+    )
+);
+($($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::DEBUG,
+        { $($k).+ = $($field)*}
+    )
+);
+(?$($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::DEBUG,
+        { ?$($k).+ = $($field)*}
+    )
+);
+(%$($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::DEBUG,
+        { %$($k).+ = $($field)*}
+    )
+);
+($($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::DEBUG,
+        { $($k).+, $($field)*}
+    )
+);
+(?$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::DEBUG,
+        { ?$($k).+, $($field)*}
+    )
+);
+(%$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::DEBUG,
+        { %$($k).+, $($field)*}
+    )
+);
+(?$($k:ident).+) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::DEBUG,
+        { ?$($k).+ }
+    )
+);
+(%$($k:ident).+) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::DEBUG,
+        { %$($k).+ }
+    )
+);
+($($k:ident).+) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::DEBUG,
+        { $($k).+ }
+    )
+);
+($($arg:tt)+) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::DEBUG,
+        $($arg)+
+    )
+);
+}
+
+#[macro_export]
+macro_rules! info {
+// Name / target / parent.
+(name: $name:expr, target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { $($field)* }, $($arg)*)
+);
+(name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { ?$($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { %$($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, {}, $($arg)+)
+);
+
+// Name / target.
+(name: $name:expr, target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::INFO, { $($field)* }, $($arg)*)
+);
+(name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::INFO, { $($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::INFO, { ?$($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::INFO, { %$($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, $($arg:tt)+ ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::INFO, {}, $($arg)+)
+);
+
+// Target / parent.
+(target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { $($field)* }, $($arg)*)
+);
+(target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)* })
+);
+(target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { ?$($k).+ $($field)* })
+);
+(target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { %$($k).+ $($field)* })
+);
+(target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, {}, $($arg)+)
+);
+
+// Name / parent.
+(name: $name:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { $($field)* }, $($arg)*)
+);
+(name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)* })
+);
+(name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { ?$($k).+ $($field)* })
+);
+(name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { %$($k).+ $($field)* })
+);
+(name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, {}, $($arg)+)
+);
+
+// Name.
+(name: $name:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(name: $name, $crate::Level::INFO, { $($field)* }, $($arg)*)
+);
+(name: $name:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, $crate::Level::INFO, { $($k).+ $($field)* })
+);
+(name: $name:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, $crate::Level::INFO, { ?$($k).+ $($field)* })
+);
+(name: $name:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, $crate::Level::INFO, { %$($k).+ $($field)* })
+);
+(name: $name:expr, $($arg:tt)+ ) => (
+    $crate::event!(name: $name, $crate::Level::INFO, {}, $($arg)+)
+);
+
+// Target.
+(target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(target: $target, $crate::Level::INFO, { $($field)* }, $($arg)*)
+);
+(target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, $crate::Level::INFO, { $($k).+ $($field)* })
+);
+(target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, $crate::Level::INFO, { ?$($k).+ $($field)* })
+);
+(target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, $crate::Level::INFO, { %$($k).+ $($field)* })
+);
+(target: $target:expr, $($arg:tt)+ ) => (
+    $crate::event!(target: $target, $crate::Level::INFO, {}, $($arg)+)
+);
+
+// Parent.
+(parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::INFO,
+        { $($field)+ },
+        $($arg)+
+    )
+);
+(parent: $parent:expr, $($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::INFO,
+        { $($k).+ = $($field)*}
+    )
+);
+(parent: $parent:expr, ?$($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::INFO,
+        { ?$($k).+ = $($field)*}
+    )
+);
+(parent: $parent:expr, %$($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::INFO,
+        { %$($k).+ = $($field)*}
+    )
+);
+(parent: $parent:expr, $($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::INFO,
+        { $($k).+, $($field)*}
+    )
+);
+(parent: $parent:expr, ?$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::INFO,
+        { ?$($k).+, $($field)*}
+    )
+);
+(parent: $parent:expr, %$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::INFO,
+        { %$($k).+, $($field)*}
+    )
+);
+(parent: $parent:expr, $($arg:tt)+) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::INFO,
+        {},
+        $($arg)+
+    )
+);
+
+// ...
+({ $($field:tt)+ }, $($arg:tt)+ ) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::INFO,
+        { $($field)+ },
+        $($arg)+
+    )
+);
+($($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::INFO,
+        { $($k).+ = $($field)*}
+    )
+);
+(?$($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::INFO,
+        { ?$($k).+ = $($field)*}
+    )
+);
+(%$($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::INFO,
+        { %$($k).+ = $($field)*}
+    )
+);
+($($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::INFO,
+        { $($k).+, $($field)*}
+    )
+);
+(?$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::INFO,
+        { ?$($k).+, $($field)*}
+    )
+);
+(%$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::INFO,
+        { %$($k).+, $($field)*}
+    )
+);
+(?$($k:ident).+) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::INFO,
+        { ?$($k).+ }
+    )
+);
+(%$($k:ident).+) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::INFO,
+        { %$($k).+ }
+    )
+);
+($($k:ident).+) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::INFO,
+        { $($k).+ }
+    )
+);
+($($arg:tt)+) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::INFO,
+        $($arg)+
+    )
+);
+}
+
+#[macro_export]
+macro_rules! warn {
+// Name / target / parent.
+(name: $name:expr, target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { $($field)* }, $($arg)*)
+);
+(name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { ?$($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { %$($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, {}, $($arg)+)
+);
+
+// Name / target.
+(name: $name:expr, target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::WARN, { $($field)* }, $($arg)*)
+);
+(name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::WARN, { $($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::WARN, { ?$($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::WARN, { %$($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, $($arg:tt)+ ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::WARN, {}, $($arg)+)
+);
+
+// Target / parent.
+(target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { $($field)* }, $($arg)*)
+);
+(target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)* })
+);
+(target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { ?$($k).+ $($field)* })
+);
+(target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { %$($k).+ $($field)* })
+);
+(target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, {}, $($arg)+)
+);
+
+// Name / parent.
+(name: $name:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { $($field)* }, $($arg)*)
+);
+(name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)* })
+);
+(name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { ?$($k).+ $($field)* })
+);
+(name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { %$($k).+ $($field)* })
+);
+(name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, {}, $($arg)+)
+);
+
+// Name.
+(name: $name:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(name: $name, $crate::Level::WARN, { $($field)* }, $($arg)*)
+);
+(name: $name:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, $crate::Level::WARN, { $($k).+ $($field)* })
+);
+(name: $name:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, $crate::Level::WARN, { ?$($k).+ $($field)* })
+);
+(name: $name:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, $crate::Level::WARN, { %$($k).+ $($field)* })
+);
+(name: $name:expr, $($arg:tt)+ ) => (
+    $crate::event!(name: $name, $crate::Level::WARN, {}, $($arg)+)
+);
+
+// Target.
+(target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(target: $target, $crate::Level::WARN, { $($field)* }, $($arg)*)
+);
+(target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, $crate::Level::WARN, { $($k).+ $($field)* })
+);
+(target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, $crate::Level::WARN, { ?$($k).+ $($field)* })
+);
+(target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, $crate::Level::WARN, { %$($k).+ $($field)* })
+);
+(target: $target:expr, $($arg:tt)+ ) => (
+    $crate::event!(target: $target, $crate::Level::WARN, {}, $($arg)+)
+);
+
+// Parent.
+(parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::WARN,
+        { $($field)+ },
+        $($arg)+
+    )
+);
+(parent: $parent:expr, $($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::WARN,
+        { $($k).+ = $($field)*}
+    )
+);
+(parent: $parent:expr, ?$($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::WARN,
+        { ?$($k).+ = $($field)*}
+    )
+);
+(parent: $parent:expr, %$($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::WARN,
+        { %$($k).+ = $($field)*}
+    )
+);
+(parent: $parent:expr, $($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::WARN,
+        { $($k).+, $($field)*}
+    )
+);
+(parent: $parent:expr, ?$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::WARN,
+        { ?$($k).+, $($field)*}
+    )
+);
+(parent: $parent:expr, %$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::WARN,
+        { %$($k).+, $($field)*}
+    )
+);
+(parent: $parent:expr, $($arg:tt)+) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::WARN,
+        {},
+        $($arg)+
+    )
+);
+
+// ...
+({ $($field:tt)+ }, $($arg:tt)+ ) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::WARN,
+        { $($field)+ },
+        $($arg)+
+    )
+);
+($($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::WARN,
+        { $($k).+ = $($field)*}
+    )
+);
+(?$($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::WARN,
+        { ?$($k).+ = $($field)*}
+    )
+);
+(%$($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::WARN,
+        { %$($k).+ = $($field)*}
+    )
+);
+($($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::WARN,
+        { $($k).+, $($field)*}
+    )
+);
+(?$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::WARN,
+        { ?$($k).+, $($field)*}
+    )
+);
+(%$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::WARN,
+        { %$($k).+, $($field)*}
+    )
+);
+(?$($k:ident).+) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::WARN,
+        { ?$($k).+ }
+    )
+);
+(%$($k:ident).+) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::WARN,
+        { %$($k).+ }
+    )
+);
+($($k:ident).+) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::WARN,
+        { $($k).+ }
+    )
+);
+($($arg:tt)+) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::WARN,
+        $($arg)+
+    )
+);
+}
+
+#[macro_export]
+macro_rules! error {
+// Name / target / parent.
+(name: $name:expr, target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { $($field)* }, $($arg)*)
+);
+(name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { ?$($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { %$($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
+    $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, {}, $($arg)+)
+);
+
+// Name / target.
+(name: $name:expr, target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { $($field)* }, $($arg)*)
+);
+(name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { $($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { ?$($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { %$($k).+ $($field)* })
+);
+(name: $name:expr, target: $target:expr, $($arg:tt)+ ) => (
+    $crate::event!(name: $name, target: $target, $crate::Level::ERROR, {}, $($arg)+)
+);
+
+// Target / parent.
+(target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { $($field)* }, $($arg)*)
+);
+(target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)* })
+);
+(target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { ?$($k).+ $($field)* })
+);
+(target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { %$($k).+ $($field)* })
+);
+(target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
+    $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, {}, $($arg)+)
+);
+
+// Name / parent.
+(name: $name:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { $($field)* }, $($arg)*)
+);
+(name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)* })
+);
+(name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { ?$($k).+ $($field)* })
+);
+(name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { %$($k).+ $($field)* })
+);
+(name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => (
+    $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, {}, $($arg)+)
+);
+
+// Name.
+(name: $name:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(name: $name, $crate::Level::ERROR, { $($field)* }, $($arg)*)
+);
+(name: $name:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, $crate::Level::ERROR, { $($k).+ $($field)* })
+);
+(name: $name:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, $crate::Level::ERROR, { ?$($k).+ $($field)* })
+);
+(name: $name:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(name: $name, $crate::Level::ERROR, { %$($k).+ $($field)* })
+);
+(name: $name:expr, $($arg:tt)+ ) => (
+    $crate::event!(name: $name, $crate::Level::ERROR, {}, $($arg)+)
+);
+
+// Target.
+(target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+    $crate::event!(target: $target, $crate::Level::ERROR, { $($field)* }, $($arg)*)
+);
+(target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, $crate::Level::ERROR, { $($k).+ $($field)* })
+);
+(target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, $crate::Level::ERROR, { ?$($k).+ $($field)* })
+);
+(target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+    $crate::event!(target: $target, $crate::Level::ERROR, { %$($k).+ $($field)* })
+);
+(target: $target:expr, $($arg:tt)+ ) => (
+    $crate::event!(target: $target, $crate::Level::ERROR, {}, $($arg)+)
+);
+
+// Parent.
+(parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::ERROR,
+        { $($field)+ },
+        $($arg)+
+    )
+);
+(parent: $parent:expr, $($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::ERROR,
+        { $($k).+ = $($field)*}
+    )
+);
+(parent: $parent:expr, ?$($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::ERROR,
+        { ?$($k).+ = $($field)*}
+    )
+);
+(parent: $parent:expr, %$($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::ERROR,
+        { %$($k).+ = $($field)*}
+    )
+);
+(parent: $parent:expr, $($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::ERROR,
+        { $($k).+, $($field)*}
+    )
+);
+(parent: $parent:expr, ?$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::ERROR,
+        { ?$($k).+, $($field)*}
+    )
+);
+(parent: $parent:expr, %$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::ERROR,
+        { %$($k).+, $($field)*}
+    )
+);
+(parent: $parent:expr, $($arg:tt)+) => (
+    $crate::event!(
+        target: module_path!(),
+        parent: $parent,
+        $crate::Level::ERROR,
+        {},
+        $($arg)+
+    )
+);
+
+// ...
+({ $($field:tt)+ }, $($arg:tt)+ ) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::ERROR,
+        { $($field)+ },
+        $($arg)+
+    )
+);
+($($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::ERROR,
+        { $($k).+ = $($field)*}
+    )
+);
+(?$($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::ERROR,
+        { ?$($k).+ = $($field)*}
+    )
+);
+(%$($k:ident).+ = $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::ERROR,
+        { %$($k).+ = $($field)*}
+    )
+);
+($($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::ERROR,
+        { $($k).+, $($field)*}
+    )
+);
+(?$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::ERROR,
+        { ?$($k).+, $($field)*}
+    )
+);
+(%$($k:ident).+, $($field:tt)*) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::ERROR,
+        { %$($k).+, $($field)*}
+    )
+);
+(?$($k:ident).+) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::ERROR,
+        { ?$($k).+ }
+    )
+);
+(%$($k:ident).+) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::ERROR,
+        { %$($k).+ }
+    )
+);
+($($k:ident).+) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::ERROR,
+        { $($k).+ }
+    )
+);
+($($arg:tt)+) => (
+    $crate::event!(
+        target: module_path!(),
+        $crate::Level::ERROR,
+        $($arg)+
+    )
+);
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! callsite {
+(name: $name:expr, kind: $kind:expr, fields: $($fields:tt)*) => {{
+    $crate::callsite! {
+        name: $name,
+        kind: $kind,
+        target: module_path!(),
+        level: $crate::Level::TRACE,
+        fields: $($fields)*
+    }
+}};
+(
+    name: $name:expr,
+    kind: $kind:expr,
+    level: $lvl:expr,
+    fields: $($fields:tt)*
+) => {{
+    $crate::callsite! {
+        name: $name,
+        kind: $kind,
+        target: module_path!(),
+        level: $lvl,
+        fields: $($fields)*
+    }
+}};
+(
+    name: $name:expr,
+    kind: $kind:expr,
+    target: $target:expr,
+    level: $lvl:expr,
+    fields: $($fields:tt)*
+) => {{
+    static META: $crate::Metadata<'static> = {
+        $crate::metadata! {
+            name: $name,
+            target: $target,
+            level: $lvl,
+            fields: $crate::fieldset!( $($fields)* ),
+            callsite: &__CALLSITE,
+            kind: $kind,
+        }
+    };
+    static __CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite::DefaultCallsite::new(&META);
+    __CALLSITE.register();
+    &__CALLSITE
+}};
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! callsite2 {
+(name: $name:expr, kind: $kind:expr, fields: $($fields:tt)*) => {{
+    $crate::callsite2! {
+        name: $name,
+        kind: $kind,
+        target: module_path!(),
+        level: $crate::Level::TRACE,
+        fields: $($fields)*
+    }
+}};
+(
+    name: $name:expr,
+    kind: $kind:expr,
+    level: $lvl:expr,
+    fields: $($fields:tt)*
+) => {{
+    $crate::callsite2! {
+        name: $name,
+        kind: $kind,
+        target: module_path!(),
+        level: $lvl,
+        fields: $($fields)*
+    }
+}};
+(
+    name: $name:expr,
+    kind: $kind:expr,
+    target: $target:expr,
+    level: $lvl:expr,
+    fields: $($fields:tt)*
+) => {{
+    static META: $crate::Metadata<'static> = {
+        $crate::metadata! {
+            name: $name,
+            target: $target,
+            level: $lvl,
+            fields: $crate::fieldset!( $($fields)* ),
+            callsite: &__CALLSITE,
+            kind: $kind,
+        }
+    };
+    $crate::callsite::DefaultCallsite::new(&META)
+}};
+}
+
+#[macro_export]
+#[doc(hidden)]
+macro_rules! level_enabled {
+($lvl:expr) => {
+    $lvl <= $crate::level_filters::STATIC_MAX_LEVEL
+        && $lvl <= $crate::level_filters::LevelFilter::current()
+};
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! valueset {
+
+// === base case ===
+(@ { $(,)* $($val:expr),* $(,)* }, $next:expr $(,)*) => {
+    &[ $($val),* ]
+};
+
+(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = ?$val:expr, $($rest:tt)*) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&debug(&$val) as &dyn Value)) },
+        $next,
+        $($rest)*
+    )
+};
+(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = %$val:expr, $($rest:tt)*) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&display(&$val) as &dyn Value)) },
+        $next,
+        $($rest)*
+    )
+};
+(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = $val:expr, $($rest:tt)*) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&$val as &dyn Value)) },
+        $next,
+        $($rest)*
+    )
+};
+(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+, $($rest:tt)*) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&$($k).+ as &dyn Value)) },
+        $next,
+        $($rest)*
+    )
+};
+(@ { $(,)* $($out:expr),* }, $next:expr, ?$($k:ident).+, $($rest:tt)*) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&debug(&$($k).+) as &dyn Value)) },
+        $next,
+        $($rest)*
+    )
+};
+(@ { $(,)* $($out:expr),* }, $next:expr, %$($k:ident).+, $($rest:tt)*) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&display(&$($k).+) as &dyn Value)) },
+        $next,
+        $($rest)*
+    )
+};
+(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = ?$val:expr) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&debug(&$val) as &dyn Value)) },
+        $next,
+    )
+};
+(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = %$val:expr) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&display(&$val) as &dyn Value)) },
+        $next,
+    )
+};
+(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = $val:expr) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&$val as &dyn Value)) },
+        $next,
+    )
+};
+(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&$($k).+ as &dyn Value)) },
+        $next,
+    )
+};
+(@ { $(,)* $($out:expr),* }, $next:expr, ?$($k:ident).+) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&debug(&$($k).+) as &dyn Value)) },
+        $next,
+    )
+};
+(@ { $(,)* $($out:expr),* }, $next:expr, %$($k:ident).+) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&display(&$($k).+) as &dyn Value)) },
+        $next,
+    )
+};
+
+// Handle literal names
+(@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = ?$val:expr, $($rest:tt)*) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&debug(&$val) as &dyn Value)) },
+        $next,
+        $($rest)*
+    )
+};
+(@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = %$val:expr, $($rest:tt)*) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&display(&$val) as &dyn Value)) },
+        $next,
+        $($rest)*
+    )
+};
+(@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = $val:expr, $($rest:tt)*) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&$val as &dyn Value)) },
+        $next,
+        $($rest)*
+    )
+};
+(@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = ?$val:expr) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&debug(&$val) as &dyn Value)) },
+        $next,
+    )
+};
+(@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = %$val:expr) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&display(&$val) as &dyn Value)) },
+        $next,
+    )
+};
+(@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = $val:expr) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&$val as &dyn Value)) },
+        $next,
+    )
+};
+
+// Handle constant names
+(@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = ?$val:expr, $($rest:tt)*) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, Some(&debug(&$val) as &dyn Value)) },
+        $next,
+        $($rest)*
+    )
+};
+(@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = %$val:expr, $($rest:tt)*) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, Some(&display(&$val) as &dyn Value)) },
+        $next,
+        $($rest)*
+    )
+};
+(@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = $val:expr, $($rest:tt)*) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, Some(&$val as &dyn Value)) },
+        $next,
+        $($rest)*
+    )
+};
+(@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = ?$val:expr) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, Some(&debug(&$val) as &dyn Value)) },
+        $next,
+    )
+};
+(@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = %$val:expr) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, Some(&display(&$val) as &dyn Value)) },
+        $next,
+    )
+};
+(@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = $val:expr) => {
+    $crate::valueset!(
+        @ { $($out),*, (&$next, Some(&$val as &dyn Value)) },
+        $next,
+    )
+};
+
+(@ { $(,)* $($out:expr),* }, $next:expr, $($rest:tt)+) => {
+    $crate::valueset!(@ { (&$next, $crate::__macro_support::Option::Some(&$crate::__macro_support::format_args!($($rest)+) as &dyn Value)), $($out),* }, $next, )
+};
+
+($fields:expr, $($kvs:tt)+) => {
+    {
+        #[allow(unused_imports)]
+        use $crate::field::{debug, display, Value};
+        let mut iter = $fields.iter();
+        $fields.value_set($crate::valueset!(
+            @ { },
+            $crate::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
+            $($kvs)+
+        ))
+    }
+};
+($fields:expr,) => {
+    {
+        $fields.value_set(&[])
+    }
+};
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! fieldset {
+(@ { $(,)* $($out:expr),* $(,)* } $(,)*) => {
+    &[ $($out),* ]
+};
+
+(@ { $(,)* $($out:expr),* } $($k:ident).+ = ?$val:expr, $($rest:tt)*) => {
+    $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*)
+};
+(@ { $(,)* $($out:expr),* } $($k:ident).+ = %$val:expr, $($rest:tt)*) => {
+    $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*)
+};
+(@ { $(,)* $($out:expr),* } $($k:ident).+ = $val:expr, $($rest:tt)*) => {
+    $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*)
+};
+(@ { $(,)* $($out:expr),* } ?$($k:ident).+, $($rest:tt)*) => {
+    $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*)
+};
+(@ { $(,)* $($out:expr),* } %$($k:ident).+, $($rest:tt)*) => {
+    $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*)
+};
+(@ { $(,)* $($out:expr),* } $($k:ident).+, $($rest:tt)*) => {
+    $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*)
+};
+
+// Handle literal names
+(@ { $(,)* $($out:expr),* } $k:literal = ?$val:expr, $($rest:tt)*) => {
+    $crate::fieldset!(@ { $($out),*, $k } $($rest)*)
+};
+(@ { $(,)* $($out:expr),* } $k:literal = %$val:expr, $($rest:tt)*) => {
+    $crate::fieldset!(@ { $($out),*, $k } $($rest)*)
+};
+(@ { $(,)* $($out:expr),* } $k:literal = $val:expr, $($rest:tt)*) => {
+    $crate::fieldset!(@ { $($out),*, $k } $($rest)*)
+};
+
+// Handle constant names
+(@ { $(,)* $($out:expr),* } { $k:expr } = ?$val:expr, $($rest:tt)*) => {
+    $crate::fieldset!(@ { $($out),*, $k } $($rest)*)
+};
+(@ { $(,)* $($out:expr),* } { $k:expr } = %$val:expr, $($rest:tt)*) => {
+    $crate::fieldset!(@ { $($out),*, $k } $($rest)*)
+};
+(@ { $(,)* $($out:expr),* } { $k:expr } = $val:expr, $($rest:tt)*) => {
+    $crate::fieldset!(@ { $($out),*, $k } $($rest)*)
+};
+
+(@ { $(,)* $($out:expr),* } $($rest:tt)+) => {
+    $crate::fieldset!(@ { "message", $($out),*, })
+};
+
+($($args:tt)*) => {
+    $crate::fieldset!(@ { } $($args)*,)
+};
+
+}
+
+#[cfg(feature = "log")]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! level_to_log {
+($level:expr) => {
+    match $level {
+        $crate::Level::ERROR => $crate::log::Level::Error,
+        $crate::Level::WARN => $crate::log::Level::Warn,
+        $crate::Level::INFO => $crate::log::Level::Info,
+        $crate::Level::DEBUG => $crate::log::Level::Debug,
+        _ => $crate::log::Level::Trace,
+    }
+};
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! __tracing_stringify {
+($($t:tt)*) => {
+    stringify!($($t)*)
+};
+}
+
+#[cfg(not(feature = "log"))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! __tracing_log {
+($level:expr, $callsite:expr, $value_set:expr) => {};
+}
+
+#[cfg(feature = "log")]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! __tracing_log {
+($level:expr, $callsite:expr, $value_set:expr) => {
+    $crate::if_log_enabled! { $level, {
+        use $crate::log;
+        let level = $crate::level_to_log!($level);
+        if level <= log::max_level() {
+            let meta = $callsite.metadata();
+            let log_meta = log::Metadata::builder()
+                .level(level)
+                .target(meta.target())
+                .build();
+            let logger = log::logger();
+            if logger.enabled(&log_meta) {
+                $crate::__macro_support::__tracing_log(meta, logger, log_meta, $value_set)
+            }
+        }
+    }}
+};
+}
+
+#[cfg(not(feature = "log"))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! if_log_enabled {
+($lvl:expr, $e:expr;) => {
+    $crate::if_log_enabled! { $lvl, $e }
+};
+($lvl:expr, $if_log:block) => {
+    $crate::if_log_enabled! { $lvl, $if_log else {} }
+};
+($lvl:expr, $if_log:block else $else_block:block) => {
+    $else_block
+};
+}
+
+#[cfg(all(feature = "log", not(feature = "log-always")))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! if_log_enabled {
+($lvl:expr, $e:expr;) => {
+    $crate::if_log_enabled! { $lvl, $e }
+};
+($lvl:expr, $if_log:block) => {
+    $crate::if_log_enabled! { $lvl, $if_log else {} }
+};
+($lvl:expr, $if_log:block else $else_block:block) => {
+    if $crate::level_to_log!($lvl) <= $crate::log::STATIC_MAX_LEVEL {
+        if !$crate::dispatcher::has_been_set() {
+            $if_log
+        } else {
+            $else_block
+        }
+    } else {
+        $else_block
+    }
+};
+}
+
+#[cfg(all(feature = "log", feature = "log-always"))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! if_log_enabled {
+($lvl:expr, $e:expr;) => {
+    $crate::if_log_enabled! { $lvl, $e }
+};
+($lvl:expr, $if_log:block) => {
+    $crate::if_log_enabled! { $lvl, $if_log else {} }
+};
+($lvl:expr, $if_log:block else $else_block:block) => {
+    if $crate::level_to_log!($lvl) <= $crate::log::STATIC_MAX_LEVEL {
+        #[allow(unused_braces)]
+        $if_log
+    } else {
+        $else_block
+    }
+};
+}
+
+//- /lib.rs crate:ra_test_fixture deps:tracing
+fn foo() {
+tracing::error!();
+}
+    "#,
+        &["E0432", "inactive-code", "unresolved-macro-call", "syntax-error", "macro-error"],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide/src/annotations.rs b/src/tools/rust-analyzer/crates/ide/src/annotations.rs
index 6a4e5ba290e..18f866eb9fc 100644
--- a/src/tools/rust-analyzer/crates/ide/src/annotations.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/annotations.rs
@@ -220,7 +220,11 @@ mod tests {
         location: AnnotationLocation::AboveName,
     };
 
-    fn check_with_config(ra_fixture: &str, expect: Expect, config: &AnnotationConfig) {
+    fn check_with_config(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        expect: Expect,
+        config: &AnnotationConfig,
+    ) {
         let (analysis, file_id) = fixture::file(ra_fixture);
 
         let annotations: Vec<Annotation> = analysis
@@ -233,7 +237,7 @@ mod tests {
         expect.assert_debug_eq(&annotations);
     }
 
-    fn check(ra_fixture: &str, expect: Expect) {
+    fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
         check_with_config(ra_fixture, expect, &DEFAULT_CONFIG);
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
index 8066894cd83..afd6f740c42 100644
--- a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
@@ -173,7 +173,7 @@ mod tests {
 
     fn check_hierarchy(
         exclude_tests: bool,
-        ra_fixture: &str,
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
         expected_nav: Expect,
         expected_incoming: Expect,
         expected_outgoing: Expect,
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
index 72fcac54177..bc9843f3f35 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -199,6 +199,7 @@ pub(crate) fn resolve_doc_path_for_def(
 ) -> Option<Definition> {
     match def {
         Definition::Module(it) => it.resolve_doc_path(db, link, ns),
+        Definition::Crate(it) => it.resolve_doc_path(db, link, ns),
         Definition::Function(it) => it.resolve_doc_path(db, link, ns),
         Definition::Adt(it) => it.resolve_doc_path(db, link, ns),
         Definition::Variant(it) => it.resolve_doc_path(db, link, ns),
@@ -594,6 +595,7 @@ fn filename_and_frag_for_def(
             Adt::Enum(e) => format!("enum.{}.html", e.name(db).unescaped().display(db.upcast())),
             Adt::Union(u) => format!("union.{}.html", u.name(db).unescaped().display(db.upcast())),
         },
+        Definition::Crate(_) => String::from("index.html"),
         Definition::Module(m) => match m.name(db) {
             // `#[doc(keyword = "...")]` is internal used only by rust compiler
             Some(name) => {
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
index fe91c81a615..d7291c4b9f3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
@@ -16,7 +16,7 @@ use crate::{
 };
 
 fn check_external_docs(
-    ra_fixture: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
     target_dir: Option<&str>,
     expect_web_url: Option<Expect>,
     expect_local_url: Option<Expect>,
@@ -41,7 +41,7 @@ fn check_external_docs(
     }
 }
 
-fn check_rewrite(ra_fixture: &str, expect: Expect) {
+fn check_rewrite(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let (analysis, position) = fixture::position(ra_fixture);
     let sema = &Semantics::new(&*analysis.db);
     let (cursor_def, docs) = def_under_cursor(sema, &position);
@@ -49,7 +49,7 @@ fn check_rewrite(ra_fixture: &str, expect: Expect) {
     expect.assert_eq(&res)
 }
 
-fn check_doc_links(ra_fixture: &str) {
+fn check_doc_links(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
     let key_fn = |&(FileRange { file_id, range }, _): &_| (file_id, range.start());
 
     let (analysis, position, mut expected) = fixture::annotations(ra_fixture);
diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
index e028c5ff0cb..0ad894427b2 100644
--- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
@@ -296,7 +296,7 @@ mod tests {
     use crate::fixture;
 
     #[track_caller]
-    fn check(ra_fixture: &str, expect: Expect) {
+    fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
         let (analysis, pos) = fixture::position(ra_fixture);
         let expansion = analysis.expand_macro(pos).unwrap().unwrap();
         let actual = format!("{}\n{}", expansion.name, expansion.expansion);
diff --git a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
index 5ef65c209ca..50977ee840c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
@@ -257,7 +257,7 @@ mod tests {
 
     use super::*;
 
-    fn check(ra_fixture: &str, expect: Expect) {
+    fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
         let file = SourceFile::parse(ra_fixture, span::Edition::CURRENT).ok().unwrap();
         let structure = file_structure(&file);
         expect.assert_debug_eq(&structure)
diff --git a/src/tools/rust-analyzer/crates/ide/src/fixture.rs b/src/tools/rust-analyzer/crates/ide/src/fixture.rs
index b16511072bd..a0612f48d37 100644
--- a/src/tools/rust-analyzer/crates/ide/src/fixture.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/fixture.rs
@@ -5,7 +5,7 @@ use test_utils::{extract_annotations, RangeOrOffset};
 use crate::{Analysis, AnalysisHost, FileId, FilePosition, FileRange};
 
 /// Creates analysis for a single file.
-pub(crate) fn file(ra_fixture: &str) -> (Analysis, FileId) {
+pub(crate) fn file(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (Analysis, FileId) {
     let mut host = AnalysisHost::default();
     let change_fixture = ChangeFixture::parse(ra_fixture);
     host.db.enable_proc_attr_macros();
@@ -14,7 +14,9 @@ pub(crate) fn file(ra_fixture: &str) -> (Analysis, FileId) {
 }
 
 /// Creates analysis from a multi-file fixture, returns positions marked with $0.
-pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) {
+pub(crate) fn position(
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+) -> (Analysis, FilePosition) {
     let mut host = AnalysisHost::default();
     let change_fixture = ChangeFixture::parse(ra_fixture);
     host.db.enable_proc_attr_macros();
@@ -25,7 +27,7 @@ pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) {
 }
 
 /// Creates analysis for a single file, returns range marked with a pair of $0.
-pub(crate) fn range(ra_fixture: &str) -> (Analysis, FileRange) {
+pub(crate) fn range(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (Analysis, FileRange) {
     let mut host = AnalysisHost::default();
     let change_fixture = ChangeFixture::parse(ra_fixture);
     host.db.enable_proc_attr_macros();
@@ -36,7 +38,9 @@ pub(crate) fn range(ra_fixture: &str) -> (Analysis, FileRange) {
 }
 
 /// Creates analysis for a single file, returns range marked with a pair of $0 or a position marked with $0.
-pub(crate) fn range_or_position(ra_fixture: &str) -> (Analysis, FileId, RangeOrOffset) {
+pub(crate) fn range_or_position(
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+) -> (Analysis, FileId, RangeOrOffset) {
     let mut host = AnalysisHost::default();
     let change_fixture = ChangeFixture::parse(ra_fixture);
     host.db.enable_proc_attr_macros();
@@ -46,7 +50,9 @@ pub(crate) fn range_or_position(ra_fixture: &str) -> (Analysis, FileId, RangeOrO
 }
 
 /// Creates analysis from a multi-file fixture, returns positions marked with $0.
-pub(crate) fn annotations(ra_fixture: &str) -> (Analysis, FilePosition, Vec<(FileRange, String)>) {
+pub(crate) fn annotations(
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+) -> (Analysis, FilePosition, Vec<(FileRange, String)>) {
     let mut host = AnalysisHost::default();
     let change_fixture = ChangeFixture::parse(ra_fixture);
     host.db.enable_proc_attr_macros();
@@ -69,7 +75,9 @@ pub(crate) fn annotations(ra_fixture: &str) -> (Analysis, FilePosition, Vec<(Fil
 }
 
 /// Creates analysis from a multi-file fixture with annotations without $0
-pub(crate) fn annotations_without_marker(ra_fixture: &str) -> (Analysis, Vec<(FileRange, String)>) {
+pub(crate) fn annotations_without_marker(
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+) -> (Analysis, Vec<(FileRange, String)>) {
     let mut host = AnalysisHost::default();
     let change_fixture = ChangeFixture::parse(ra_fixture);
     host.db.enable_proc_attr_macros();
diff --git a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs
index c1b7693a650..e5a94ff9fe9 100755
--- a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs
@@ -286,7 +286,7 @@ mod tests {
 
     use super::*;
 
-    fn check(ra_fixture: &str) {
+    fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         let (ranges, text) = extract_tags(ra_fixture, "fold");
 
         let parse = SourceFile::parse(&text, span::Edition::CURRENT);
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
index 7b6a5ef13e5..3742edc8db8 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
@@ -83,7 +83,7 @@ mod tests {
 
     use crate::fixture;
 
-    fn check(ra_fixture: &str) {
+    fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         let (analysis, position, expected) = fixture::annotations(ra_fixture);
         let navs = analysis
             .goto_declaration(position)
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
index 6c66907ec3e..f804cc36772 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -81,6 +81,10 @@ pub(crate) fn goto_definition(
         return Some(RangeInfo::new(original_token.text_range(), navs));
     }
 
+    if let Some(navs) = find_definition_for_known_blanket_dual_impls(sema, &original_token) {
+        return Some(RangeInfo::new(original_token.text_range(), navs));
+    }
+
     let navs = sema
         .descend_into_macros_no_opaque(original_token.clone())
         .into_iter()
@@ -125,6 +129,18 @@ pub(crate) fn goto_definition(
     Some(RangeInfo::new(original_token.text_range(), navs))
 }
 
+// If the token is into(), try_into(), parse(), search the definition of From, TryFrom, FromStr.
+fn find_definition_for_known_blanket_dual_impls(
+    sema: &Semantics<'_, RootDatabase>,
+    original_token: &SyntaxToken,
+) -> Option<Vec<NavigationTarget>> {
+    let method_call = ast::MethodCallExpr::cast(original_token.parent()?.parent()?)?;
+    let target_method = sema.resolve_known_blanket_dual_impls(&method_call)?;
+
+    let def = Definition::from(target_method);
+    Some(def_to_nav(sema.db, def))
+}
+
 fn try_lookup_include_path(
     sema: &Semantics<'_, RootDatabase>,
     token: ast::String,
@@ -424,7 +440,7 @@ mod tests {
     use syntax::SmolStr;
 
     #[track_caller]
-    fn check(ra_fixture: &str) {
+    fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         let (analysis, position, expected) = fixture::annotations(ra_fixture);
         let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
 
@@ -443,14 +459,14 @@ mod tests {
         assert_eq!(expected, navs);
     }
 
-    fn check_unresolved(ra_fixture: &str) {
+    fn check_unresolved(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         let (analysis, position) = fixture::position(ra_fixture);
         let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
 
         assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {navs:?}")
     }
 
-    fn check_name(expected_name: &str, ra_fixture: &str) {
+    fn check_name(expected_name: &str, #[rust_analyzer::rust_fixture] ra_fixture: &str) {
         let (analysis, position, _) = fixture::annotations(ra_fixture);
         let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
         assert!(navs.len() < 2, "expected single navigation target but encountered {}", navs.len());
@@ -3022,4 +3038,150 @@ fn foo() {
 "#,
         );
     }
+    #[test]
+    fn into_call_to_from_definition() {
+        check(
+            r#"
+//- minicore: from
+struct A;
+
+struct B;
+
+impl From<A> for B {
+    fn from(value: A) -> Self {
+     //^^^^
+        B
+    }
+}
+
+fn f() {
+    let a = A;
+    let b: B = a.into$0();
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn into_call_to_from_definition_with_trait_bounds() {
+        check(
+            r#"
+//- minicore: from, iterator
+struct A;
+
+impl<T> From<T> for A
+where
+    T: IntoIterator<Item = i64>,
+{
+    fn from(value: T) -> Self {
+     //^^^^
+        A
+    }
+}
+
+fn f() {
+    let a: A = [1, 2, 3].into$0();
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn goto_into_definition_if_exists() {
+        check(
+            r#"
+//- minicore: from
+struct A;
+
+struct B;
+
+impl Into<B> for A {
+    fn into(self) -> B {
+     //^^^^
+        B
+    }
+}
+
+fn f() {
+    let a = A;
+    let b: B = a.into$0();
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn try_into_call_to_try_from_definition() {
+        check(
+            r#"
+//- minicore: from
+struct A;
+
+struct B;
+
+impl TryFrom<A> for B {
+    type Error = String;
+
+    fn try_from(value: A) -> Result<Self, Self::Error> {
+     //^^^^^^^^
+        Ok(B)
+    }
+}
+
+fn f() {
+    let a = A;
+    let b: Result<B, _> = a.try_into$0();
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn goto_try_into_definition_if_exists() {
+        check(
+            r#"
+//- minicore: from
+struct A;
+
+struct B;
+
+impl TryInto<B> for A {
+    type Error = String;
+
+    fn try_into(self) -> Result<B, Self::Error> {
+     //^^^^^^^^
+        Ok(B)
+    }
+}
+
+fn f() {
+    let a = A;
+    let b: Result<B, _> = a.try_into$0();
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn parse_call_to_from_str_definition() {
+        check(
+            r#"
+//- minicore: from, str
+struct A;
+
+impl FromStr for A {
+    type Error = String;
+
+    fn from_str(value: &str) -> Result<Self, Self::Error> {
+     //^^^^^^^^
+        Ok(A)
+    }
+}
+
+fn f() {
+    let a: Result<A, _> = "aaaaaa".parse$0();
+}
+        "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
index 04da1f67e95..e926378367e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
@@ -129,7 +129,7 @@ mod tests {
 
     use crate::fixture;
 
-    fn check(ra_fixture: &str) {
+    fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         let (analysis, position, expected) = fixture::annotations(ra_fixture);
 
         let navs = analysis.goto_implementation(position).unwrap().unwrap().info;
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
index c7ebd9a3531..2610d6c8863 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
@@ -24,9 +24,10 @@ pub(crate) fn goto_type_definition(
     let file: ast::SourceFile = sema.parse_guess_edition(file_id);
     let token: SyntaxToken =
         pick_best_token(file.syntax().token_at_offset(offset), |kind| match kind {
-            IDENT | INT_NUMBER | T![self] => 2,
+            IDENT | INT_NUMBER | T![self] => 3,
             kind if kind.is_trivia() => 0,
-            _ => 1,
+            T![;] => 1,
+            _ => 2,
         })?;
 
     let mut res = Vec::new();
@@ -118,7 +119,7 @@ mod tests {
 
     use crate::fixture;
 
-    fn check(ra_fixture: &str) {
+    fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         let (analysis, position, expected) = fixture::annotations(ra_fixture);
         let navs = analysis.goto_type_definition(position).unwrap().unwrap().info;
         assert!(!navs.is_empty(), "navigation is empty");
diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
index 4002cbebad6..612bc36f628 100644
--- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
@@ -684,12 +684,15 @@ mod tests {
     };
 
     #[track_caller]
-    fn check(ra_fixture: &str) {
+    fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         check_with_config(ra_fixture, ENABLED_CONFIG);
     }
 
     #[track_caller]
-    fn check_with_config(ra_fixture: &str, config: HighlightRelatedConfig) {
+    fn check_with_config(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        config: HighlightRelatedConfig,
+    ) {
         let (analysis, pos, annotations) = fixture::annotations(ra_fixture);
 
         let hls = analysis.highlight_related(config, pos).unwrap().unwrap_or_default();
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 1431bd8ca29..18a3fed07ec 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -6,7 +6,9 @@ mod tests;
 use std::{iter, ops::Not};
 
 use either::Either;
-use hir::{db::DefDatabase, GenericSubstitution, HasCrate, HasSource, LangItem, Semantics};
+use hir::{
+    db::DefDatabase, GenericDef, GenericSubstitution, HasCrate, HasSource, LangItem, Semantics,
+};
 use ide_db::{
     defs::{Definition, IdentClass, NameRefClass, OperatorClass},
     famous_defs::FamousDefs,
@@ -548,24 +550,29 @@ fn goto_type_action_for_def(
         });
     }
 
-    if let Definition::GenericParam(hir::GenericParam::TypeParam(it)) = def {
-        let krate = it.module(db).krate();
-        let sized_trait =
-            db.lang_item(krate.into(), LangItem::Sized).and_then(|lang_item| lang_item.as_trait());
-
-        it.trait_bounds(db)
-            .into_iter()
-            .filter(|&it| Some(it.into()) != sized_trait)
-            .for_each(|it| push_new_def(it.into()));
-    } else {
-        let ty = match def {
-            Definition::Local(it) => it.ty(db),
-            Definition::GenericParam(hir::GenericParam::ConstParam(it)) => it.ty(db),
-            Definition::Field(field) => field.ty(db),
-            Definition::Function(function) => function.ret_type(db),
-            _ => return HoverAction::goto_type_from_targets(db, targets, edition),
-        };
+    if let Ok(generic_def) = GenericDef::try_from(def) {
+        generic_def.type_or_const_params(db).into_iter().for_each(|it| {
+            walk_and_push_ty(db, &it.ty(db), &mut push_new_def);
+        });
+    }
 
+    let ty = match def {
+        Definition::Local(it) => Some(it.ty(db)),
+        Definition::Field(field) => Some(field.ty(db)),
+        Definition::TupleField(field) => Some(field.ty(db)),
+        Definition::Const(it) => Some(it.ty(db)),
+        Definition::Static(it) => Some(it.ty(db)),
+        Definition::Function(func) => {
+            for param in func.assoc_fn_params(db) {
+                walk_and_push_ty(db, param.ty(), &mut push_new_def);
+            }
+            Some(func.ret_type(db))
+        }
+        Definition::GenericParam(hir::GenericParam::ConstParam(it)) => Some(it.ty(db)),
+        Definition::GenericParam(hir::GenericParam::TypeParam(it)) => Some(it.ty(db)),
+        _ => None,
+    };
+    if let Some(ty) = ty {
         walk_and_push_ty(db, &ty, &mut push_new_def);
     }
 
@@ -592,6 +599,14 @@ fn walk_and_push_ty(
             traits.for_each(|it| push_new_def(it.into()));
         } else if let Some(trait_) = t.as_associated_type_parent_trait(db) {
             push_new_def(trait_.into());
+        } else if let Some(tp) = t.as_type_param(db) {
+            let sized_trait = db
+                .lang_item(t.krate(db).into(), LangItem::Sized)
+                .and_then(|lang_item| lang_item.as_trait());
+            tp.trait_bounds(db)
+                .into_iter()
+                .filter(|&it| Some(it.into()) != sized_trait)
+                .for_each(|it| push_new_def(it.into()));
         }
     });
 }
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 8fbd445d962..46242b75dd0 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, AssocItemContainer, CaptureKind,
+    db::ExpandDatabase, Adt, AsAssocItem, AsExternAssocItem, CaptureKind,
     DynCompatibilityViolation, HasCrate, HasSource, HirDisplay, Layout, LayoutError,
     MethodViolationCode, Name, Semantics, Symbol, Trait, Type, TypeInfo, VariantDef,
 };
@@ -376,7 +376,7 @@ pub(super) fn process_markup(
     Markup::from(markup)
 }
 
-fn definition_owner_name(db: &RootDatabase, def: &Definition, edition: Edition) -> Option<String> {
+fn definition_owner_name(db: &RootDatabase, def: Definition, edition: Edition) -> Option<String> {
     match def {
         Definition::Field(f) => {
             let parent = f.parent_def(db);
@@ -390,9 +390,52 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition, edition: Edition)
                 _ => Some(parent_name),
             };
         }
-        Definition::Local(l) => l.parent(db).name(db),
         Definition::Variant(e) => Some(e.parent_enum(db).name(db)),
-
+        Definition::GenericParam(generic_param) => match generic_param.parent() {
+            hir::GenericDef::Adt(it) => Some(it.name(db)),
+            hir::GenericDef::Trait(it) => Some(it.name(db)),
+            hir::GenericDef::TraitAlias(it) => Some(it.name(db)),
+            hir::GenericDef::TypeAlias(it) => Some(it.name(db)),
+
+            hir::GenericDef::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)),
+            hir::GenericDef::Function(it) => {
+                let container = it.as_assoc_item(db).and_then(|assoc| match assoc.container(db) {
+                    hir::AssocItemContainer::Trait(t) => Some(t.name(db)),
+                    hir::AssocItemContainer::Impl(i) => {
+                        i.self_ty(db).as_adt().map(|adt| adt.name(db))
+                    }
+                });
+                match container {
+                    Some(name) => {
+                        return Some(format!(
+                            "{}::{}",
+                            name.display(db, edition),
+                            it.name(db).display(db, edition)
+                        ))
+                    }
+                    None => Some(it.name(db)),
+                }
+            }
+            hir::GenericDef::Const(it) => {
+                let container = it.as_assoc_item(db).and_then(|assoc| match assoc.container(db) {
+                    hir::AssocItemContainer::Trait(t) => Some(t.name(db)),
+                    hir::AssocItemContainer::Impl(i) => {
+                        i.self_ty(db).as_adt().map(|adt| adt.name(db))
+                    }
+                });
+                match container {
+                    Some(name) => {
+                        return Some(format!(
+                            "{}::{}",
+                            name.display(db, edition),
+                            it.name(db)?.display(db, edition)
+                        ))
+                    }
+                    None => it.name(db),
+                }
+            }
+        },
+        Definition::DeriveHelper(derive_helper) => Some(derive_helper.derive().name(db)),
         d => {
             if let Some(assoc_item) = d.as_assoc_item(db) {
                 match assoc_item.container(db) {
@@ -436,7 +479,7 @@ pub(super) fn definition(
     config: &HoverConfig,
     edition: Edition,
 ) -> Markup {
-    let mod_path = definition_mod_path(db, &def, edition);
+    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()
@@ -915,19 +958,22 @@ fn closure_ty(
     Some(res)
 }
 
-fn definition_mod_path(db: &RootDatabase, def: &Definition, edition: Edition) -> Option<String> {
-    if matches!(def, Definition::GenericParam(_) | Definition::Local(_) | Definition::Label(_)) {
+fn definition_path(db: &RootDatabase, &def: &Definition, edition: Edition) -> Option<String> {
+    if matches!(
+        def,
+        Definition::TupleField(_)
+            | Definition::Label(_)
+            | Definition::Local(_)
+            | Definition::BuiltinAttr(_)
+            | Definition::BuiltinLifetime(_)
+            | Definition::BuiltinType(_)
+            | Definition::InlineAsmRegOrRegClass(_)
+            | Definition::InlineAsmOperand(_)
+    ) {
         return None;
     }
-    let container: Option<Definition> =
-        def.as_assoc_item(db).and_then(|assoc| match assoc.container(db) {
-            AssocItemContainer::Trait(trait_) => Some(trait_.into()),
-            AssocItemContainer::Impl(impl_) => impl_.self_ty(db).as_adt().map(|adt| adt.into()),
-        });
-    container
-        .unwrap_or(*def)
-        .module(db)
-        .map(|module| path(db, module, definition_owner_name(db, def, edition), edition))
+    let rendered_parent = definition_owner_name(db, def, edition);
+    def.module(db).map(|module| path(db, module, rendered_parent, edition))
 }
 
 fn markup(
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 2e7637e4677..014b751f95b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -23,7 +23,7 @@ const HOVER_BASE_CONFIG: HoverConfig = HoverConfig {
     max_subst_ty_len: super::SubstTyLen::Unlimited,
 };
 
-fn check_hover_no_result(ra_fixture: &str) {
+fn check_hover_no_result(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
     let (analysis, position) = fixture::position(ra_fixture);
     let hover = analysis
         .hover(
@@ -35,7 +35,7 @@ fn check_hover_no_result(ra_fixture: &str) {
 }
 
 #[track_caller]
-fn check(ra_fixture: &str, expect: Expect) {
+fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let (analysis, position) = fixture::position(ra_fixture);
     let hover = analysis
         .hover(
@@ -55,7 +55,7 @@ fn check(ra_fixture: &str, expect: Expect) {
 #[track_caller]
 fn check_hover_fields_limit(
     fields_count: impl Into<Option<usize>>,
-    ra_fixture: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
     expect: Expect,
 ) {
     let (analysis, position) = fixture::position(ra_fixture);
@@ -81,7 +81,7 @@ fn check_hover_fields_limit(
 #[track_caller]
 fn check_hover_enum_variants_limit(
     variants_count: impl Into<Option<usize>>,
-    ra_fixture: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
     expect: Expect,
 ) {
     let (analysis, position) = fixture::position(ra_fixture);
@@ -105,7 +105,11 @@ fn check_hover_enum_variants_limit(
 }
 
 #[track_caller]
-fn check_assoc_count(count: usize, ra_fixture: &str, expect: Expect) {
+fn check_assoc_count(
+    count: usize,
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    expect: Expect,
+) {
     let (analysis, position) = fixture::position(ra_fixture);
     let hover = analysis
         .hover(
@@ -126,7 +130,7 @@ fn check_assoc_count(count: usize, ra_fixture: &str, expect: Expect) {
     expect.assert_eq(&actual)
 }
 
-fn check_hover_no_links(ra_fixture: &str, expect: Expect) {
+fn check_hover_no_links(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let (analysis, position) = fixture::position(ra_fixture);
     let hover = analysis
         .hover(
@@ -143,7 +147,7 @@ fn check_hover_no_links(ra_fixture: &str, expect: Expect) {
     expect.assert_eq(&actual)
 }
 
-fn check_hover_no_memory_layout(ra_fixture: &str, expect: Expect) {
+fn check_hover_no_memory_layout(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let (analysis, position) = fixture::position(ra_fixture);
     let hover = analysis
         .hover(
@@ -160,7 +164,7 @@ fn check_hover_no_memory_layout(ra_fixture: &str, expect: Expect) {
     expect.assert_eq(&actual)
 }
 
-fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) {
+fn check_hover_no_markdown(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let (analysis, position) = fixture::position(ra_fixture);
     let hover = analysis
         .hover(
@@ -181,7 +185,7 @@ fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) {
     expect.assert_eq(&actual)
 }
 
-fn check_actions(ra_fixture: &str, expect: Expect) {
+fn check_actions(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let (analysis, file_id, position) = fixture::range_or_position(ra_fixture);
     let mut hover = analysis
         .hover(
@@ -206,13 +210,13 @@ fn check_actions(ra_fixture: &str, expect: Expect) {
     expect.assert_debug_eq(&hover.info.actions)
 }
 
-fn check_hover_range(ra_fixture: &str, expect: Expect) {
+fn check_hover_range(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let (analysis, range) = fixture::range(ra_fixture);
     let hover = analysis.hover(&HOVER_BASE_CONFIG, range).unwrap().unwrap();
     expect.assert_eq(hover.info.markup.as_str())
 }
 
-fn check_hover_range_actions(ra_fixture: &str, expect: Expect) {
+fn check_hover_range_actions(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let (analysis, range) = fixture::range(ra_fixture);
     let mut hover = analysis
         .hover(&HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG }, range)
@@ -234,7 +238,7 @@ fn check_hover_range_actions(ra_fixture: &str, expect: Expect) {
     expect.assert_debug_eq(&hover.info.actions);
 }
 
-fn check_hover_range_no_results(ra_fixture: &str) {
+fn check_hover_range_no_results(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
     let (analysis, range) = fixture::range(ra_fixture);
     let hover = analysis.hover(&HOVER_BASE_CONFIG, range).unwrap();
     assert!(hover.is_none());
@@ -2365,6 +2369,97 @@ fn test() {
 }
 
 #[test]
+fn test_hover_show_type_def_for_func_param() {
+    check_actions(
+        r#"
+struct Bar;
+fn f(b: Bar) {
+
+}
+
+fn test() {
+    let b = Bar;
+    f$0(b);
+}
+"#,
+        expect![[r#"
+            [
+                Reference(
+                    FilePositionWrapper {
+                        file_id: FileId(
+                            0,
+                        ),
+                        offset: 15,
+                    },
+                ),
+                GoToType(
+                    [
+                        HoverGotoTypeData {
+                            mod_path: "ra_test_fixture::Bar",
+                            nav: NavigationTarget {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                full_range: 0..11,
+                                focus_range: 7..10,
+                                name: "Bar",
+                                kind: Struct,
+                                description: "struct Bar",
+                            },
+                        },
+                    ],
+                ),
+            ]
+        "#]],
+    );
+}
+
+#[test]
+fn test_hover_show_type_def_for_trait_bound() {
+    check_actions(
+        r#"
+trait Bar {}
+fn f<T: Bar>(b: T) {
+
+}
+
+fn test() {
+    f$0();
+}
+"#,
+        expect![[r#"
+            [
+                Reference(
+                    FilePositionWrapper {
+                        file_id: FileId(
+                            0,
+                        ),
+                        offset: 16,
+                    },
+                ),
+                GoToType(
+                    [
+                        HoverGotoTypeData {
+                            mod_path: "ra_test_fixture::Bar",
+                            nav: NavigationTarget {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                full_range: 0..12,
+                                focus_range: 6..9,
+                                name: "Bar",
+                                kind: Trait,
+                                description: "trait Bar",
+                            },
+                        },
+                    ],
+                ),
+            ]
+        "#]],
+    );
+}
+
+#[test]
 fn test_hover_non_ascii_space_doc() {
     check(
         "
@@ -4700,6 +4795,10 @@ fn hover_lifetime() {
             *'lifetime*
 
             ```rust
+            ra_test_fixture::foo
+            ```
+
+            ```rust
             'lifetime
             ```
         "#]],
@@ -4730,6 +4829,10 @@ impl<T: TraitA + TraitB> Foo<T$0> where T: Sized {}
             *T*
 
             ```rust
+            ra_test_fixture::Foo
+            ```
+
+            ```rust
             T: TraitA + TraitB
             ```
         "#]],
@@ -4744,6 +4847,10 @@ impl<T> Foo<T$0> {}
             *T*
 
             ```rust
+            ra_test_fixture::Foo
+            ```
+
+            ```rust
             T
             ```
         "#]],
@@ -4758,6 +4865,10 @@ impl<T: 'static> Foo<T$0> {}
             *T*
 
             ```rust
+            ra_test_fixture::Foo
+            ```
+
+            ```rust
             T: 'static
             ```
         "#]],
@@ -4778,6 +4889,10 @@ impl<T$0: Trait> Foo<T> {}
             *T*
 
             ```rust
+            ra_test_fixture::Foo
+            ```
+
+            ```rust
             T: Trait
             ```
         "#]],
@@ -4793,6 +4908,10 @@ impl<T$0: Trait + ?Sized> Foo<T> {}
             *T*
 
             ```rust
+            ra_test_fixture::Foo
+            ```
+
+            ```rust
             T: Trait + ?Sized
             ```
         "#]],
@@ -4813,6 +4932,10 @@ fn foo<T$0>() {}
                 *T*
 
                 ```rust
+                ra_test_fixture::foo
+                ```
+
+                ```rust
                 T
                 ```
 
@@ -4834,6 +4957,10 @@ fn foo<T$0: Sized>() {}
                 *T*
 
                 ```rust
+                ra_test_fixture::foo
+                ```
+
+                ```rust
                 T
                 ```
 
@@ -4855,6 +4982,10 @@ fn foo<T$0: ?Sized>() {}
                 *T*
 
                 ```rust
+                ra_test_fixture::foo
+                ```
+
+                ```rust
                 T: ?Sized
                 ```
 
@@ -4877,6 +5008,10 @@ fn foo<T$0: Trait>() {}
                 *T*
 
                 ```rust
+                ra_test_fixture::foo
+                ```
+
+                ```rust
                 T: Trait
                 ```
 
@@ -4899,6 +5034,10 @@ fn foo<T$0: Trait + Sized>() {}
                 *T*
 
                 ```rust
+                ra_test_fixture::foo
+                ```
+
+                ```rust
                 T: Trait
                 ```
 
@@ -4921,6 +5060,10 @@ fn foo<T$0: Trait + ?Sized>() {}
                 *T*
 
                 ```rust
+                ra_test_fixture::foo
+                ```
+
+                ```rust
                 T: Trait + ?Sized
                 ```
 
@@ -4942,6 +5085,10 @@ fn foo<T$0: ?Sized + Sized + Sized>() {}
                 *T*
 
                 ```rust
+                ra_test_fixture::foo
+                ```
+
+                ```rust
                 T
                 ```
 
@@ -4964,6 +5111,10 @@ fn foo<T$0: Sized + ?Sized + Sized + Trait>() {}
                 *T*
 
                 ```rust
+                ra_test_fixture::foo
+                ```
+
+                ```rust
                 T: Trait
                 ```
 
@@ -5011,6 +5162,10 @@ impl<const LEN: usize> Foo<LEN$0> {}
             *LEN*
 
             ```rust
+            ra_test_fixture::Foo
+            ```
+
+            ```rust
             const LEN: usize
             ```
         "#]],
@@ -6112,7 +6267,7 @@ use foo::bar::{self$0};
             ```
 
             ```rust
-            mod bar
+            pub mod bar
             ```
 
             ---
@@ -7857,7 +8012,7 @@ fn test() {
             *foo*
 
             ```rust
-            ra_test_fixture::S
+            ra_test_fixture::m::S
             ```
 
             ```rust
@@ -7886,7 +8041,7 @@ fn test() {
             *foo*
 
             ```rust
-            ra_test_fixture::S
+            ra_test_fixture::m::S
             ```
 
             ```rust
@@ -7916,7 +8071,7 @@ mod m {
             *foo*
 
             ```rust
-            ra_test_fixture::S
+            ra_test_fixture::m::inner::S
             ```
 
             ```rust
@@ -7946,7 +8101,7 @@ fn test() {
             *A*
 
             ```rust
-            ra_test_fixture::S
+            ra_test_fixture::m::S
             ```
 
             ```rust
@@ -7975,7 +8130,7 @@ fn test() {
             *A*
 
             ```rust
-            ra_test_fixture::S
+            ra_test_fixture::m::S
             ```
 
             ```rust
@@ -8005,7 +8160,7 @@ mod m {
             *A*
 
             ```rust
-            ra_test_fixture::S
+            ra_test_fixture::m::inner::S
             ```
 
             ```rust
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 faa65019eea..6d83a747d76 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -1,6 +1,6 @@
 use std::{
     fmt::{self, Write},
-    mem::take,
+    mem::{self, take},
 };
 
 use either::Either;
@@ -24,6 +24,7 @@ use crate::{navigation_target::TryToNav, FileId};
 mod adjustment;
 mod bind_pat;
 mod binding_mode;
+mod bounds;
 mod chaining;
 mod closing_brace;
 mod closure_captures;
@@ -111,6 +112,9 @@ pub(crate) fn inlay_hints(
         }
         hints(event);
     }
+    if let Some(range_limit) = range_limit {
+        acc.retain(|hint| range_limit.contains_range(hint.range));
+    }
     acc
 }
 
@@ -264,6 +268,7 @@ fn hints(
                 ast::Type::PathType(path) => lifetime::fn_path_hints(hints, ctx, famous_defs, config, file_id, path),
                 _ => Some(()),
             },
+            ast::GenericParamList(it) => bounds::hints(hints, famous_defs, config, file_id, it),
             _ => Some(()),
         }
     };
@@ -273,6 +278,7 @@ fn hints(
 pub struct InlayHintsConfig {
     pub render_colons: bool,
     pub type_hints: bool,
+    pub sized_bound: bool,
     pub discriminant_hints: DiscriminantHints,
     pub parameter_hints: bool,
     pub generic_parameter_hints: GenericParameterHints,
@@ -294,6 +300,36 @@ pub struct InlayHintsConfig {
     pub closing_brace_hints_min_lines: Option<usize>,
     pub fields_to_resolve: InlayFieldsToResolve,
 }
+impl InlayHintsConfig {
+    fn lazy_text_edit(&self, finish: impl FnOnce() -> TextEdit) -> Lazy<TextEdit> {
+        if self.fields_to_resolve.resolve_text_edits {
+            Lazy::Lazy
+        } else {
+            let edit = finish();
+            never!(edit.is_empty(), "inlay hint produced an empty text edit");
+            Lazy::Computed(edit)
+        }
+    }
+
+    fn lazy_tooltip(&self, finish: impl FnOnce() -> InlayTooltip) -> Lazy<InlayTooltip> {
+        if self.fields_to_resolve.resolve_hint_tooltip
+            && self.fields_to_resolve.resolve_label_tooltip
+        {
+            Lazy::Lazy
+        } else {
+            let tooltip = finish();
+            never!(
+                match &tooltip {
+                    InlayTooltip::String(s) => s,
+                    InlayTooltip::Markdown(s) => s,
+                }
+                .is_empty(),
+                "inlay hint produced an empty tooltip"
+            );
+            Lazy::Computed(tooltip)
+        }
+    }
+}
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub struct InlayFieldsToResolve {
@@ -405,12 +441,32 @@ pub struct InlayHint {
     /// The actual label to show in the inlay hint.
     pub label: InlayHintLabel,
     /// Text edit to apply when "accepting" this inlay hint.
-    pub text_edit: Option<TextEdit>,
+    pub text_edit: Option<Lazy<TextEdit>>,
     /// Range to recompute inlay hints when trying to resolve for this hint. If this is none, the
     /// hint does not support resolving.
     pub resolve_parent: Option<TextRange>,
 }
 
+/// A type signaling that a value is either computed, or is available for computation.
+#[derive(Clone, Debug)]
+pub enum Lazy<T> {
+    Computed(T),
+    Lazy,
+}
+
+impl<T> Lazy<T> {
+    pub fn computed(self) -> Option<T> {
+        match self {
+            Lazy::Computed(it) => Some(it),
+            _ => None,
+        }
+    }
+
+    pub fn is_lazy(&self) -> bool {
+        matches!(self, Self::Lazy)
+    }
+}
+
 impl std::hash::Hash for InlayHint {
     fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
         self.range.hash(state);
@@ -419,7 +475,7 @@ impl std::hash::Hash for InlayHint {
         self.pad_right.hash(state);
         self.kind.hash(state);
         self.label.hash(state);
-        self.text_edit.is_some().hash(state);
+        mem::discriminant(&self.text_edit).hash(state);
     }
 }
 
@@ -436,10 +492,6 @@ impl InlayHint {
             resolve_parent: None,
         }
     }
-
-    pub fn needs_resolve(&self) -> Option<TextRange> {
-        self.resolve_parent.filter(|_| self.text_edit.is_some() || self.label.needs_resolve())
-    }
 }
 
 #[derive(Debug, Hash)]
@@ -456,7 +508,7 @@ pub struct InlayHintLabel {
 impl InlayHintLabel {
     pub fn simple(
         s: impl Into<String>,
-        tooltip: Option<InlayTooltip>,
+        tooltip: Option<Lazy<InlayTooltip>>,
         linked_location: Option<FileRange>,
     ) -> InlayHintLabel {
         InlayHintLabel {
@@ -500,10 +552,6 @@ impl InlayHintLabel {
         }
         self.parts.push(part);
     }
-
-    pub fn needs_resolve(&self) -> bool {
-        self.parts.iter().any(|part| part.linked_location.is_some() || part.tooltip.is_some())
-    }
 }
 
 impl From<String> for InlayHintLabel {
@@ -538,7 +586,6 @@ impl fmt::Debug for InlayHintLabel {
     }
 }
 
-#[derive(Hash)]
 pub struct InlayHintLabelPart {
     pub text: String,
     /// Source location represented by this label part. The client will use this to fetch the part's
@@ -549,13 +596,21 @@ pub struct InlayHintLabelPart {
     pub linked_location: Option<FileRange>,
     /// The tooltip to show when hovering over the inlay hint, this may invoke other actions like
     /// hover requests to show.
-    pub tooltip: Option<InlayTooltip>,
+    pub tooltip: Option<Lazy<InlayTooltip>>,
+}
+
+impl std::hash::Hash for InlayHintLabelPart {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.text.hash(state);
+        self.linked_location.hash(state);
+        self.tooltip.is_some().hash(state);
+    }
 }
 
 impl fmt::Debug for InlayHintLabelPart {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            Self { text, linked_location: None, tooltip: None } => text.fmt(f),
+            Self { text, linked_location: None, tooltip: None | Some(Lazy::Lazy) } => text.fmt(f),
             Self { text, linked_location, tooltip } => f
                 .debug_struct("InlayHintLabelPart")
                 .field("text", text)
@@ -563,7 +618,8 @@ impl fmt::Debug for InlayHintLabelPart {
                 .field(
                     "tooltip",
                     &tooltip.as_ref().map_or("", |it| match it {
-                        InlayTooltip::String(it) | InlayTooltip::Markdown(it) => it,
+                        Lazy::Computed(InlayTooltip::String(it) | InlayTooltip::Markdown(it)) => it,
+                        Lazy::Lazy => "",
                     }),
                 )
                 .finish(),
@@ -722,19 +778,22 @@ fn hint_iterator(
 
 fn ty_to_text_edit(
     sema: &Semantics<'_, RootDatabase>,
+    config: &InlayHintsConfig,
     node_for_hint: &SyntaxNode,
     ty: &hir::Type,
     offset_to_insert: TextSize,
-    prefix: String,
-) -> Option<TextEdit> {
-    let scope = sema.scope(node_for_hint)?;
+    prefix: impl Into<String>,
+) -> Option<Lazy<TextEdit>> {
     // FIXME: Limit the length and bail out on excess somehow?
-    let rendered = ty.display_source_code(scope.db, scope.module().into(), false).ok()?;
-
-    let mut builder = TextEdit::builder();
-    builder.insert(offset_to_insert, prefix);
-    builder.insert(offset_to_insert, rendered);
-    Some(builder.finish())
+    let rendered = sema
+        .scope(node_for_hint)
+        .and_then(|scope| ty.display_source_code(scope.db, scope.module().into(), false).ok())?;
+    Some(config.lazy_text_edit(|| {
+        let mut builder = TextEdit::builder();
+        builder.insert(offset_to_insert, prefix.into());
+        builder.insert(offset_to_insert, rendered);
+        builder.finish()
+    }))
 }
 
 fn closure_has_block_body(closure: &ast::ClosureExpr) -> bool {
@@ -760,6 +819,7 @@ mod tests {
         render_colons: false,
         type_hints: false,
         parameter_hints: false,
+        sized_bound: false,
         generic_parameter_hints: GenericParameterHints {
             type_hints: false,
             lifetime_hints: false,
@@ -794,12 +854,15 @@ mod tests {
     };
 
     #[track_caller]
-    pub(super) fn check(ra_fixture: &str) {
+    pub(super) fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         check_with_config(TEST_CONFIG, ra_fixture);
     }
 
     #[track_caller]
-    pub(super) fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) {
+    pub(super) fn check_with_config(
+        config: InlayHintsConfig,
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    ) {
         let (analysis, file_id) = fixture::file(ra_fixture);
         let mut expected = extract_annotations(&analysis.file_text(file_id).unwrap());
         let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
@@ -814,16 +877,33 @@ mod tests {
         assert_eq!(expected, actual, "\nExpected:\n{expected:#?}\n\nActual:\n{actual:#?}");
     }
 
+    #[track_caller]
+    pub(super) fn check_expect(
+        config: InlayHintsConfig,
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        expect: Expect,
+    ) {
+        let (analysis, file_id) = fixture::file(ra_fixture);
+        let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
+        let filtered =
+            inlay_hints.into_iter().map(|hint| (hint.range, hint.label)).collect::<Vec<_>>();
+        expect.assert_debug_eq(&filtered)
+    }
+
     /// Computes inlay hints for the fixture, applies all the provided text edits and then runs
     /// expect test.
     #[track_caller]
-    pub(super) fn check_edit(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) {
+    pub(super) fn check_edit(
+        config: InlayHintsConfig,
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        expect: Expect,
+    ) {
         let (analysis, file_id) = fixture::file(ra_fixture);
         let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
 
         let edits = inlay_hints
             .into_iter()
-            .filter_map(|hint| hint.text_edit)
+            .filter_map(|hint| hint.text_edit?.computed())
             .reduce(|mut acc, next| {
                 acc.union(next).expect("merging text edits failed");
                 acc
@@ -836,11 +916,15 @@ mod tests {
     }
 
     #[track_caller]
-    pub(super) fn check_no_edit(config: InlayHintsConfig, ra_fixture: &str) {
+    pub(super) fn check_no_edit(
+        config: InlayHintsConfig,
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    ) {
         let (analysis, file_id) = fixture::file(ra_fixture);
         let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
 
-        let edits: Vec<_> = inlay_hints.into_iter().filter_map(|hint| hint.text_edit).collect();
+        let edits: Vec<_> =
+            inlay_hints.into_iter().filter_map(|hint| hint.text_edit?.computed()).collect();
 
         assert!(edits.is_empty(), "unexpected edits: {edits:?}");
     }
@@ -870,4 +954,17 @@ fn foo() {
 "#,
         );
     }
+
+    #[test]
+    fn regression_18898() {
+        check(
+            r#"
+//- proc_macros: issue_18898
+#[proc_macros::issue_18898]
+fn foo() {
+    let
+}
+"#,
+        );
+    }
 }
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 4e48baa6f14..2acd4021cc1 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
@@ -162,11 +162,13 @@ pub(super) fn hints(
         let label = InlayHintLabelPart {
             text: if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() },
             linked_location: None,
-            tooltip: Some(InlayTooltip::Markdown(format!(
-                "`{}` → `{}` ({coercion} coercion)",
-                source.display(sema.db, file_id.edition()),
-                target.display(sema.db, file_id.edition()),
-            ))),
+            tooltip: Some(config.lazy_tooltip(|| {
+                InlayTooltip::Markdown(format!(
+                    "`{}` → `{}` ({coercion} coercion)",
+                    source.display(sema.db, file_id.edition()),
+                    target.display(sema.db, file_id.edition()),
+                ))
+            })),
         };
         if postfix { &mut post } else { &mut pre }.label.append_part(label);
     }
@@ -183,7 +185,7 @@ pub(super) fn hints(
         return None;
     }
     if allow_edit {
-        let edit = {
+        let edit = Some(config.lazy_text_edit(|| {
             let mut b = TextEditBuilder::default();
             if let Some(pre) = &pre {
                 b.insert(
@@ -198,14 +200,14 @@ pub(super) fn hints(
                 );
             }
             b.finish()
-        };
+        }));
         match (&mut pre, &mut post) {
             (Some(pre), Some(post)) => {
-                pre.text_edit = Some(edit.clone());
-                post.text_edit = Some(edit);
+                pre.text_edit = edit.clone();
+                post.text_edit = edit;
             }
-            (Some(pre), None) => pre.text_edit = Some(edit),
-            (None, Some(post)) => post.text_edit = Some(edit),
+            (Some(pre), None) => pre.text_edit = edit,
+            (None, Some(post)) => post.text_edit = edit,
             (None, None) => (),
         }
     }
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 7a808fb4a92..ab5464156f0 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
@@ -78,13 +78,14 @@ pub(super) fn hints(
     let text_edit = if let Some(colon_token) = &type_ascriptable {
         ty_to_text_edit(
             sema,
+            config,
             desc_pat.syntax(),
             &ty,
             colon_token
                 .as_ref()
                 .map_or_else(|| pat.syntax().text_range(), |t| t.text_range())
                 .end(),
-            if colon_token.is_some() { String::new() } else { String::from(": ") },
+            if colon_token.is_some() { "" } else { ": " },
         )
     } else {
         None
@@ -185,7 +186,7 @@ mod tests {
     };
 
     #[track_caller]
-    fn check_types(ra_fixture: &str) {
+    fn check_types(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         check_with_config(InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, ra_fixture);
     }
 
@@ -391,36 +392,37 @@ fn main() {
     #[test]
     fn check_hint_range_limit() {
         let fixture = r#"
-        //- minicore: fn, sized
-        fn foo() -> impl Fn() { loop {} }
-        fn foo1() -> impl Fn(f64) { loop {} }
-        fn foo2() -> impl Fn(f64, f64) { loop {} }
-        fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
-        fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
-        fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
-        fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
-        fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
-
-        fn main() {
-            let foo = foo();
-            let foo = foo1();
-            let foo = foo2();
-             // ^^^ impl Fn(f64, f64)
-            let foo = foo3();
-             // ^^^ impl Fn(f64, f64) -> u32
-            let foo = foo4();
-            let foo = foo5();
-            let foo = foo6();
-            let foo = foo7();
-        }
-        "#;
+//- minicore: fn, sized
+fn foo() -> impl Fn() { loop {} }
+fn foo1() -> impl Fn(f64) { loop {} }
+fn foo2() -> impl Fn(f64, f64) { loop {} }
+fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
+fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
+fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
+fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
+fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
+
+fn main() {
+    let foo = foo();
+    let foo = foo1();
+    let foo = foo2();
+     // ^^^ impl Fn(f64, f64)
+    let foo = foo3();
+     // ^^^ impl Fn(f64, f64) -> u32
+    let foo = foo4();
+     // ^^^ &dyn Fn(f64, f64) -> u32
+    let foo = foo5();
+    let foo = foo6();
+    let foo = foo7();
+}
+"#;
         let (analysis, file_id) = fixture::file(fixture);
         let expected = extract_annotations(&analysis.file_text(file_id).unwrap());
         let inlay_hints = analysis
             .inlay_hints(
                 &InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
                 file_id,
-                Some(TextRange::new(TextSize::from(500), TextSize::from(600))),
+                Some(TextRange::new(TextSize::from(491), TextSize::from(640))),
             )
             .unwrap();
         let actual =
@@ -1163,4 +1165,45 @@ fn main() {
 }"#,
         );
     }
+
+    #[test]
+    fn collapses_nested_impl_projections() {
+        check_types(
+            r#"
+//- minicore: sized
+trait T {
+    type Assoc;
+    fn f(self) -> Self::Assoc;
+}
+
+trait T2 {}
+trait T3<T> {}
+
+fn f(it: impl T<Assoc: T2>) {
+    let l = it.f();
+     // ^ impl T2
+}
+
+fn f2<G: T<Assoc: T2 + 'static>>(it: G) {
+    let l = it.f();
+      //^ impl T2 + 'static
+}
+
+fn f3<G: T>(it: G) where <G as T>::Assoc: T2 {
+    let l = it.f();
+      //^ impl T2
+}
+
+fn f4<G: T<Assoc: T2 + T3<()>>>(it: G) {
+    let l = it.f();
+      //^ impl T2 + T3<()>
+}
+
+fn f5<G: T<Assoc = ()>>(it: G) {
+    let l = it.f();
+      //^ ()
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
index 5afb98cb1c7..5bbb4fe4e66 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
@@ -99,17 +99,24 @@ pub(super) fn hints(
     }
 
     if let hints @ [_, ..] = &mut acc[acc_base..] {
-        let mut edit = TextEditBuilder::default();
-        for h in &mut *hints {
-            edit.insert(
-                match h.position {
-                    InlayHintPosition::Before => h.range.start(),
-                    InlayHintPosition::After => h.range.end(),
-                },
-                h.label.parts.iter().map(|p| &*p.text).collect(),
-            );
-        }
-        let edit = edit.finish();
+        let edit = config.lazy_text_edit(|| {
+            let mut edit = TextEditBuilder::default();
+            for h in &mut *hints {
+                edit.insert(
+                    match h.position {
+                        InlayHintPosition::Before => h.range.start(),
+                        InlayHintPosition::After => h.range.end(),
+                    },
+                    h.label
+                        .parts
+                        .iter()
+                        .map(|p| &*p.text)
+                        .chain(h.pad_right.then_some(" "))
+                        .collect(),
+                );
+            }
+            edit.finish()
+        });
         hints.iter_mut().for_each(|h| h.text_edit = Some(edit.clone()));
     }
 
@@ -118,8 +125,10 @@ pub(super) fn hints(
 
 #[cfg(test)]
 mod tests {
+    use expect_test::expect;
+
     use crate::{
-        inlay_hints::tests::{check_with_config, DISABLED_CONFIG},
+        inlay_hints::tests::{check_edit, check_with_config, DISABLED_CONFIG},
         InlayHintsConfig,
     };
 
@@ -194,4 +203,27 @@ fn foo(s @ Struct { field, .. }: &Struct) {}
 "#,
         );
     }
+
+    #[test]
+    fn edits() {
+        check_edit(
+            InlayHintsConfig { binding_mode_hints: true, ..DISABLED_CONFIG },
+            r#"
+fn main() {
+    match &(0,) {
+        (x,) | (x,) => (),
+        ((x,) | (x,)) => (),
+    }
+}
+"#,
+            expect![[r#"
+                fn main() {
+                    match &(0,) {
+                        &(&((ref x,) | (ref x,))) => (),
+                        &((ref x,) | (ref x,)) => (),
+                    }
+                }
+            "#]],
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs
new file mode 100644
index 00000000000..429ddd31cbd
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs
@@ -0,0 +1,152 @@
+//! Implementation of trait bound hints.
+//!
+//! Currently this renders the implied `Sized` bound.
+use ide_db::{famous_defs::FamousDefs, FileRange};
+
+use span::EditionedFileId;
+use syntax::ast::{self, AstNode, HasTypeBounds};
+
+use crate::{
+    InlayHint, InlayHintLabel, InlayHintLabelPart, InlayHintPosition, InlayHintsConfig, InlayKind,
+    TryToNav,
+};
+
+pub(super) fn hints(
+    acc: &mut Vec<InlayHint>,
+    famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
+    config: &InlayHintsConfig,
+    _file_id: EditionedFileId,
+    params: ast::GenericParamList,
+) -> Option<()> {
+    if !config.sized_bound {
+        return None;
+    }
+
+    let linked_location =
+        famous_defs.core_marker_Sized().and_then(|it| it.try_to_nav(sema.db)).map(|it| {
+            let n = it.call_site();
+            FileRange { file_id: n.file_id, range: n.focus_or_full_range() }
+        });
+
+    for param in params.type_or_const_params() {
+        match param {
+            ast::TypeOrConstParam::Type(type_param) => {
+                let c = type_param.colon_token().map(|it| it.text_range());
+                let has_bounds =
+                    type_param.type_bound_list().is_some_and(|it| it.bounds().next().is_some());
+                acc.push(InlayHint {
+                    range: c.unwrap_or_else(|| type_param.syntax().text_range()),
+                    kind: InlayKind::Type,
+                    label: {
+                        let mut hint = InlayHintLabel::default();
+                        if c.is_none() {
+                            hint.parts.push(InlayHintLabelPart {
+                                text: ": ".to_owned(),
+                                linked_location: None,
+                                tooltip: None,
+                            });
+                        }
+                        hint.parts.push(InlayHintLabelPart {
+                            text: "Sized".to_owned(),
+                            linked_location,
+                            tooltip: None,
+                        });
+                        if has_bounds {
+                            hint.parts.push(InlayHintLabelPart {
+                                text: " +".to_owned(),
+                                linked_location: None,
+                                tooltip: None,
+                            });
+                        }
+                        hint
+                    },
+                    text_edit: None,
+                    position: InlayHintPosition::After,
+                    pad_left: c.is_some(),
+                    pad_right: has_bounds,
+                    resolve_parent: Some(params.syntax().text_range()),
+                });
+            }
+            ast::TypeOrConstParam::Const(_) => (),
+        }
+    }
+
+    Some(())
+}
+
+#[cfg(test)]
+mod tests {
+    use expect_test::expect;
+
+    use crate::inlay_hints::InlayHintsConfig;
+
+    use crate::inlay_hints::tests::{check_expect, check_with_config, DISABLED_CONFIG};
+
+    #[track_caller]
+    fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
+        check_with_config(InlayHintsConfig { sized_bound: true, ..DISABLED_CONFIG }, ra_fixture);
+    }
+
+    #[test]
+    fn smoke() {
+        check(
+            r#"
+fn foo<T>() {}
+    // ^ : Sized
+"#,
+        );
+    }
+
+    #[test]
+    fn with_colon() {
+        check(
+            r#"
+fn foo<T:>() {}
+     // ^ Sized
+"#,
+        );
+    }
+
+    #[test]
+    fn with_colon_and_bounds() {
+        check(
+            r#"
+fn foo<T: 'static>() {}
+     // ^ Sized +
+"#,
+        );
+    }
+
+    #[test]
+    fn location_works() {
+        check_expect(
+            InlayHintsConfig { sized_bound: true, ..DISABLED_CONFIG },
+            r#"
+//- minicore: sized
+fn foo<T>() {}
+"#,
+            expect![[r#"
+                [
+                    (
+                        7..8,
+                        [
+                            ": ",
+                            InlayHintLabelPart {
+                                text: "Sized",
+                                linked_location: Some(
+                                    FileRangeWrapper {
+                                        file_id: FileId(
+                                            1,
+                                        ),
+                                        range: 135..140,
+                                    },
+                                ),
+                                tooltip: "",
+                            },
+                        ],
+                    ),
+                ]
+            "#]],
+        );
+    }
+}
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 028ed1650f4..7fa7ab1a94d 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
@@ -81,28 +81,19 @@ mod tests {
 
     use crate::{
         fixture,
-        inlay_hints::tests::{check_with_config, DISABLED_CONFIG, TEST_CONFIG},
+        inlay_hints::tests::{check_expect, check_with_config, DISABLED_CONFIG, TEST_CONFIG},
         InlayHintsConfig,
     };
 
     #[track_caller]
-    fn check_chains(ra_fixture: &str) {
+    fn check_chains(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         check_with_config(InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG }, ra_fixture);
     }
 
     #[track_caller]
-    pub(super) fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) {
-        let (analysis, file_id) = fixture::file(ra_fixture);
-        let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
-        let filtered =
-            inlay_hints.into_iter().map(|hint| (hint.range, hint.label)).collect::<Vec<_>>();
-        expect.assert_debug_eq(&filtered)
-    }
-
-    #[track_caller]
     pub(super) fn check_expect_clear_loc(
         config: InlayHintsConfig,
-        ra_fixture: &str,
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
         expect: Expect,
     ) {
         let (analysis, file_id) = fixture::file(ra_fixture);
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 6827540fa82..7858b1d90a3 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
@@ -52,13 +52,14 @@ pub(super) fn hints(
     let text_edit = if has_block_body {
         ty_to_text_edit(
             sema,
+            config,
             closure.syntax(),
             &ty,
             arrow
                 .as_ref()
                 .map_or_else(|| param_list.syntax().text_range(), |t| t.text_range())
                 .end(),
-            if arrow.is_none() { String::from(" -> ") } else { String::new() },
+            if arrow.is_none() { " -> " } else { "" },
         )
     } else {
         None
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
index 8f2949cb387..f1e1955d14c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
@@ -36,13 +36,14 @@ pub(super) fn enum_hints(
         return None;
     }
     for variant in enum_.variant_list()?.variants() {
-        variant_hints(acc, sema, &enum_, &variant);
+        variant_hints(acc, config, sema, &enum_, &variant);
     }
     Some(())
 }
 
 fn variant_hints(
     acc: &mut Vec<InlayHint>,
+    config: &InlayHintsConfig,
     sema: &Semantics<'_, RootDatabase>,
     enum_: &ast::Enum,
     variant: &ast::Variant,
@@ -75,9 +76,11 @@ fn variant_hints(
             }
             Err(_) => format!("{eq_} ?"),
         },
-        Some(InlayTooltip::String(match &d {
-            Ok(_) => "enum variant discriminant".into(),
-            Err(e) => format!("{e:?}"),
+        Some(config.lazy_tooltip(|| {
+            InlayTooltip::String(match &d {
+                Ok(_) => "enum variant discriminant".into(),
+                Err(e) => format!("{e:?}"),
+            })
         })),
         None,
     );
@@ -88,7 +91,9 @@ fn variant_hints(
         },
         kind: InlayKind::Discriminant,
         label,
-        text_edit: d.ok().map(|val| TextEdit::insert(range.start(), format!("{eq_} {val}"))),
+        text_edit: d.ok().map(|val| {
+            config.lazy_text_edit(|| TextEdit::insert(range.end(), format!("{eq_} {val}")))
+        }),
         position: InlayHintPosition::After,
         pad_left: false,
         pad_right: false,
@@ -99,13 +104,15 @@ fn variant_hints(
 }
 #[cfg(test)]
 mod tests {
+    use expect_test::expect;
+
     use crate::inlay_hints::{
-        tests::{check_with_config, DISABLED_CONFIG},
+        tests::{check_edit, check_with_config, DISABLED_CONFIG},
         DiscriminantHints, InlayHintsConfig,
     };
 
     #[track_caller]
-    fn check_discriminants(ra_fixture: &str) {
+    fn check_discriminants(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         check_with_config(
             InlayHintsConfig { discriminant_hints: DiscriminantHints::Always, ..DISABLED_CONFIG },
             ra_fixture,
@@ -113,7 +120,7 @@ mod tests {
     }
 
     #[track_caller]
-    fn check_discriminants_fieldless(ra_fixture: &str) {
+    fn check_discriminants_fieldless(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         check_with_config(
             InlayHintsConfig {
                 discriminant_hints: DiscriminantHints::Fieldless,
@@ -207,4 +214,33 @@ enum Enum {
 "#,
         );
     }
+
+    #[test]
+    fn edit() {
+        check_edit(
+            InlayHintsConfig { discriminant_hints: DiscriminantHints::Always, ..DISABLED_CONFIG },
+            r#"
+#[repr(u8)]
+enum Enum {
+    Variant(),
+    Variant1,
+    Variant2 {},
+    Variant3,
+    Variant5,
+    Variant6,
+}
+"#,
+            expect![[r#"
+                #[repr(u8)]
+                enum Enum {
+                    Variant() = 0,
+                    Variant1 = 1,
+                    Variant2 {} = 2,
+                    Variant3 = 3,
+                    Variant5 = 4,
+                    Variant6 = 5,
+                }
+            "#]],
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs
index 4cc4925cda6..2bc91b68ed8 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs
@@ -8,7 +8,7 @@ use crate::{InlayHint, InlayHintsConfig};
 pub(super) fn extern_block_hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(_sema, _): &FamousDefs<'_, '_>,
-    _config: &InlayHintsConfig,
+    config: &InlayHintsConfig,
     _file_id: EditionedFileId,
     extern_block: ast::ExternBlock,
 ) -> Option<()> {
@@ -23,7 +23,9 @@ pub(super) fn extern_block_hints(
         pad_right: true,
         kind: crate::InlayKind::ExternUnsafety,
         label: crate::InlayHintLabel::from("unsafe"),
-        text_edit: Some(TextEdit::insert(abi.syntax().text_range().start(), "unsafe ".to_owned())),
+        text_edit: Some(config.lazy_text_edit(|| {
+            TextEdit::insert(abi.syntax().text_range().start(), "unsafe ".to_owned())
+        })),
         resolve_parent: Some(extern_block.syntax().text_range()),
     });
     Some(())
@@ -32,7 +34,7 @@ pub(super) fn extern_block_hints(
 pub(super) fn fn_hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(_sema, _): &FamousDefs<'_, '_>,
-    _config: &InlayHintsConfig,
+    config: &InlayHintsConfig,
     _file_id: EditionedFileId,
     fn_: &ast::Fn,
     extern_block: &ast::ExternBlock,
@@ -42,14 +44,14 @@ pub(super) fn fn_hints(
         return None;
     }
     let fn_ = fn_.fn_token()?;
-    acc.push(item_hint(extern_block, fn_));
+    acc.push(item_hint(config, extern_block, fn_));
     Some(())
 }
 
 pub(super) fn static_hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(_sema, _): &FamousDefs<'_, '_>,
-    _config: &InlayHintsConfig,
+    config: &InlayHintsConfig,
     _file_id: EditionedFileId,
     static_: &ast::Static,
     extern_block: &ast::ExternBlock,
@@ -59,11 +61,15 @@ pub(super) fn static_hints(
         return None;
     }
     let static_ = static_.static_token()?;
-    acc.push(item_hint(extern_block, static_));
+    acc.push(item_hint(config, extern_block, static_));
     Some(())
 }
 
-fn item_hint(extern_block: &ast::ExternBlock, token: SyntaxToken) -> InlayHint {
+fn item_hint(
+    config: &InlayHintsConfig,
+    extern_block: &ast::ExternBlock,
+    token: SyntaxToken,
+) -> InlayHint {
     InlayHint {
         range: token.text_range(),
         position: crate::InlayHintPosition::Before,
@@ -71,7 +77,7 @@ fn item_hint(extern_block: &ast::ExternBlock, token: SyntaxToken) -> InlayHint {
         pad_right: true,
         kind: crate::InlayKind::ExternUnsafety,
         label: crate::InlayHintLabel::from("unsafe"),
-        text_edit: {
+        text_edit: Some(config.lazy_text_edit(|| {
             let mut builder = TextEdit::builder();
             builder.insert(token.text_range().start(), "unsafe ".to_owned());
             if extern_block.unsafe_token().is_none() {
@@ -79,8 +85,8 @@ fn item_hint(extern_block: &ast::ExternBlock, token: SyntaxToken) -> InlayHint {
                     builder.insert(abi.syntax().text_range().start(), "unsafe ".to_owned());
                 }
             }
-            Some(builder.finish())
-        },
+            builder.finish()
+        })),
         resolve_parent: Some(extern_block.syntax().text_range()),
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs
index ed7ebc3b1e7..037b328d971 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs
@@ -142,7 +142,7 @@ mod tests {
     };
 
     #[track_caller]
-    fn generic_param_name_hints_always(ra_fixture: &str) {
+    fn generic_param_name_hints_always(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         check_with_config(
             InlayHintsConfig {
                 generic_parameter_hints: GenericParameterHints {
@@ -157,7 +157,7 @@ mod tests {
     }
 
     #[track_caller]
-    fn generic_param_name_hints_const_only(ra_fixture: &str) {
+    fn generic_param_name_hints_const_only(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         check_with_config(
             InlayHintsConfig {
                 generic_parameter_hints: GenericParameterHints {
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
index dd4b3efeecf..1358d3722f8 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
@@ -108,7 +108,7 @@ pub(super) fn hints(
             }
             let mut label = InlayHintLabel::simple(
                 name,
-                Some(crate::InlayTooltip::String("moz".into())),
+                Some(config.lazy_tooltip(|| crate::InlayTooltip::String("moz".into()))),
                 binding_source,
             );
             label.prepend_str("drop(");
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
index 1560df37d0d..ae5b519b43d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
@@ -39,7 +39,9 @@ pub(super) fn hints(
                 range: t.text_range(),
                 kind: InlayKind::Lifetime,
                 label: "'static".into(),
-                text_edit: Some(TextEdit::insert(t.text_range().start(), "'static ".into())),
+                text_edit: Some(config.lazy_text_edit(|| {
+                    TextEdit::insert(t.text_range().start(), "'static ".into())
+                })),
                 position: InlayHintPosition::After,
                 pad_left: false,
                 pad_right: true,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
index a03ff6a52b4..a7b066700c5 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
@@ -269,7 +269,7 @@ mod tests {
     };
 
     #[track_caller]
-    fn check_params(ra_fixture: &str) {
+    fn check_params(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         check_with_config(
             InlayHintsConfig { parameter_hints: true, ..DISABLED_CONFIG },
             ra_fixture,
diff --git a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
index 5192f91a4a6..e4670177ecf 100644
--- a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
@@ -307,7 +307,10 @@ mod tests {
 
     use super::*;
 
-    fn check_join_lines(ra_fixture_before: &str, ra_fixture_after: &str) {
+    fn check_join_lines(
+        #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+        #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
+    ) {
         let config = JoinLinesConfig {
             join_else_if: true,
             remove_trailing_comma: true,
@@ -333,7 +336,10 @@ mod tests {
         assert_eq_text!(ra_fixture_after, &actual);
     }
 
-    fn check_join_lines_sel(ra_fixture_before: &str, ra_fixture_after: &str) {
+    fn check_join_lines_sel(
+        #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+        #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
+    ) {
         let config = JoinLinesConfig {
             join_else_if: true,
             remove_trailing_comma: true,
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index 6e7c718953c..346e2862b0f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -48,7 +48,6 @@ mod ssr;
 mod static_index;
 mod status;
 mod syntax_highlighting;
-mod syntax_tree;
 mod test_explorer;
 mod typing;
 mod view_crate_graph;
@@ -56,6 +55,7 @@ mod view_hir;
 mod view_item_tree;
 mod view_memory_layout;
 mod view_mir;
+mod view_syntax_tree;
 
 use std::{iter, panic::UnwindSafe};
 
@@ -120,7 +120,7 @@ pub use ide_assists::{
 };
 pub use ide_completion::{
     CallableSnippets, CompletionConfig, CompletionFieldsToResolve, CompletionItem,
-    CompletionItemKind, CompletionRelevance, Snippet, SnippetScope,
+    CompletionItemKind, CompletionItemRefMode, CompletionRelevance, Snippet, SnippetScope,
 };
 pub use ide_db::text_edit::{Indel, TextEdit};
 pub use ide_db::{
@@ -329,14 +329,8 @@ impl Analysis {
         })
     }
 
-    /// Returns a syntax tree represented as `String`, for debug purposes.
-    // FIXME: use a better name here.
-    pub fn syntax_tree(
-        &self,
-        file_id: FileId,
-        text_range: Option<TextRange>,
-    ) -> Cancellable<String> {
-        self.with_db(|db| syntax_tree::syntax_tree(db, file_id, text_range))
+    pub fn view_syntax_tree(&self, file_id: FileId) -> Cancellable<String> {
+        self.with_db(|db| view_syntax_tree::view_syntax_tree(db, file_id))
     }
 
     pub fn view_hir(&self, position: FilePosition) -> Cancellable<String> {
@@ -410,17 +404,11 @@ impl Analysis {
         &self,
         position: FilePosition,
         char_typed: char,
-        chars_to_exclude: Option<String>,
     ) -> Cancellable<Option<SourceChange>> {
         // Fast path to not even parse the file.
         if !typing::TRIGGER_CHARS.contains(char_typed) {
             return Ok(None);
         }
-        if let Some(chars_to_exclude) = chars_to_exclude {
-            if chars_to_exclude.contains(char_typed) {
-                return Ok(None);
-            }
-        }
 
         self.with_db(|db| typing::on_char_typed(db, position, char_typed))
     }
@@ -588,17 +576,17 @@ impl Analysis {
         self.with_db(|db| parent_module::parent_module(db, position))
     }
 
-    /// Returns crates this file belongs too.
+    /// Returns crates that this file belongs to.
     pub fn crates_for(&self, file_id: FileId) -> Cancellable<Vec<CrateId>> {
         self.with_db(|db| parent_module::crates_for(db, file_id))
     }
 
-    /// Returns crates this file belongs too.
+    /// Returns crates that this file belongs to.
     pub fn transitive_rev_deps(&self, crate_id: CrateId) -> Cancellable<Vec<CrateId>> {
         self.with_db(|db| db.crate_graph().transitive_rev_deps(crate_id).collect())
     }
 
-    /// Returns crates this file *might* belong too.
+    /// Returns crates that this file *might* belong to.
     pub fn relevant_crates_for(&self, file_id: FileId) -> Cancellable<Vec<CrateId>> {
         self.with_db(|db| db.relevant_crates(file_id).iter().copied().collect())
     }
diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs
index 052466725fa..d97c12ebafb 100644
--- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs
@@ -191,7 +191,7 @@ pub(crate) fn def_to_kind(db: &RootDatabase, def: Definition) -> SymbolInformati
             MacroKind::ProcMacro => Macro,
         },
         Definition::Field(..) | Definition::TupleField(..) => Field,
-        Definition::Module(..) => Module,
+        Definition::Module(..) | Definition::Crate(..) => Module,
         Definition::Function(it) => {
             if it.as_assoc_item(db).is_some() {
                 if it.has_self_param(db) {
@@ -405,7 +405,7 @@ mod tests {
 
     #[allow(dead_code)]
     #[track_caller]
-    fn no_moniker(ra_fixture: &str) {
+    fn no_moniker(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         let (analysis, position) = fixture::position(ra_fixture);
         if let Some(x) = analysis.moniker(position).unwrap() {
             assert_eq!(x.info.len(), 0, "Moniker found but no moniker expected: {x:?}");
@@ -413,7 +413,12 @@ mod tests {
     }
 
     #[track_caller]
-    fn check_local_moniker(ra_fixture: &str, identifier: &str, package: &str, kind: MonikerKind) {
+    fn check_local_moniker(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        identifier: &str,
+        package: &str,
+        kind: MonikerKind,
+    ) {
         let (analysis, position) = fixture::position(ra_fixture);
         let x = analysis.moniker(position).unwrap().expect("no moniker found").info;
         assert_eq!(x.len(), 1);
@@ -433,7 +438,12 @@ mod tests {
     }
 
     #[track_caller]
-    fn check_moniker(ra_fixture: &str, identifier: &str, package: &str, kind: MonikerKind) {
+    fn check_moniker(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        identifier: &str,
+        package: &str,
+        kind: MonikerKind,
+    ) {
         let (analysis, position) = fixture::position(ra_fixture);
         let x = analysis.moniker(position).unwrap().expect("no moniker found").info;
         assert_eq!(x.len(), 1);
diff --git a/src/tools/rust-analyzer/crates/ide/src/move_item.rs b/src/tools/rust-analyzer/crates/ide/src/move_item.rs
index a232df2b82b..b0df9257ba1 100644
--- a/src/tools/rust-analyzer/crates/ide/src/move_item.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/move_item.rs
@@ -180,7 +180,11 @@ mod tests {
 
     use crate::Direction;
 
-    fn check(ra_fixture: &str, expect: Expect, direction: Direction) {
+    fn check(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        expect: Expect,
+        direction: Direction,
+    ) {
         let (analysis, range) = fixture::range(ra_fixture);
         let edit = analysis.move_item(range, direction).unwrap().unwrap_or_default();
         let mut file = analysis.file_text(range.file_id).unwrap().to_string();
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 9259243db85..d9f80cb53dd 100644
--- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
@@ -44,13 +44,16 @@ pub struct NavigationTarget {
     ///
     /// This range must be contained within [`Self::full_range`].
     pub focus_range: Option<TextRange>,
+    // FIXME: Symbol
     pub name: SmolStr,
     pub kind: Option<SymbolKind>,
+    // FIXME: Symbol
     pub container_name: Option<SmolStr>,
     pub description: Option<String>,
     pub docs: Option<Documentation>,
     /// In addition to a `name` field, a `NavigationTarget` may also be aliased
     /// In such cases we want a `NavigationTarget` to be accessible by its alias
+    // FIXME: Symbol
     pub alias: Option<SmolStr>,
 }
 
@@ -191,11 +194,11 @@ impl TryToNav for FileSymbol {
                 NavigationTarget {
                     file_id,
                     name: self.is_alias.then(|| self.def.name(db)).flatten().map_or_else(
-                        || self.name.clone(),
+                        || self.name.as_str().into(),
                         |it| it.display_no_db(edition).to_smolstr(),
                     ),
-                    alias: self.is_alias.then(|| self.name.clone()),
-                    kind: Some(hir::ModuleDefId::from(self.def).into()),
+                    alias: self.is_alias.then(|| self.name.as_str().into()),
+                    kind: Some(self.def.into()),
                     full_range,
                     focus_range,
                     container_name: self.container_name.clone(),
@@ -225,6 +228,7 @@ impl TryToNav for Definition {
             Definition::Local(it) => Some(it.to_nav(db)),
             Definition::Label(it) => it.try_to_nav(db),
             Definition::Module(it) => Some(it.to_nav(db)),
+            Definition::Crate(it) => Some(it.to_nav(db)),
             Definition::Macro(it) => it.try_to_nav(db),
             Definition::Field(it) => it.try_to_nav(db),
             Definition::SelfType(it) => it.try_to_nav(db),
@@ -398,6 +402,12 @@ impl ToNav for hir::Module {
     }
 }
 
+impl ToNav for hir::Crate {
+    fn to_nav(&self, db: &RootDatabase) -> UpmappingResult<NavigationTarget> {
+        self.root_module().to_nav(db)
+    }
+}
+
 impl TryToNav for hir::Impl {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
         let InFile { file_id, value } = self.source(db)?;
diff --git a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
index b51a5cc4f4c..7a0c28d925a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
@@ -70,7 +70,7 @@ mod tests {
 
     use crate::fixture;
 
-    fn check(ra_fixture: &str) {
+    fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         let (analysis, position, expected) = fixture::annotations(ra_fixture);
         let navs = analysis.parent_module(position).unwrap();
         let navs = navs
diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs
index 46714df8d69..b1079312d3b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/references.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/references.rs
@@ -1255,11 +1255,15 @@ impl Foo {
         );
     }
 
-    fn check(ra_fixture: &str, expect: Expect) {
+    fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
         check_with_scope(ra_fixture, None, expect)
     }
 
-    fn check_with_scope(ra_fixture: &str, search_scope: Option<SearchScope>, expect: Expect) {
+    fn check_with_scope(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        search_scope: Option<SearchScope>,
+        expect: Expect,
+    ) {
         let (analysis, pos) = fixture::position(ra_fixture);
         let refs = analysis.find_all_refs(pos, search_scope).unwrap().unwrap();
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs
index 11bbd99110b..ba739df3092 100644
--- a/src/tools/rust-analyzer/crates/ide/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs
@@ -456,7 +456,11 @@ mod tests {
     use super::{RangeInfo, RenameError};
 
     #[track_caller]
-    fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
+    fn check(
+        new_name: &str,
+        #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+        #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
+    ) {
         let ra_fixture_after = &trim_indent(ra_fixture_after);
         let (analysis, position) = fixture::position(ra_fixture_before);
         if !ra_fixture_after.starts_with("error: ") {
@@ -494,14 +498,22 @@ mod tests {
         };
     }
 
-    fn check_expect(new_name: &str, ra_fixture: &str, expect: Expect) {
+    fn check_expect(
+        new_name: &str,
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        expect: Expect,
+    ) {
         let (analysis, position) = fixture::position(ra_fixture);
         let source_change =
             analysis.rename(position, new_name).unwrap().expect("Expect returned a RenameError");
         expect.assert_eq(&filter_expect(source_change))
     }
 
-    fn check_expect_will_rename_file(new_name: &str, ra_fixture: &str, expect: Expect) {
+    fn check_expect_will_rename_file(
+        new_name: &str,
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        expect: Expect,
+    ) {
         let (analysis, position) = fixture::position(ra_fixture);
         let source_change = analysis
             .will_rename_file(position.file_id, new_name)
@@ -510,7 +522,7 @@ mod tests {
         expect.assert_eq(&filter_expect(source_change))
     }
 
-    fn check_prepare(ra_fixture: &str, expect: Expect) {
+    fn check_prepare(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
         let (analysis, position) = fixture::position(ra_fixture);
         let result = analysis
             .prepare_rename(position)
diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
index 3e39c750b13..32edacee51c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
@@ -748,7 +748,7 @@ mod tests {
 
     use crate::fixture;
 
-    fn check(ra_fixture: &str, expect: Expect) {
+    fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
         let (analysis, position) = fixture::position(ra_fixture);
         let result = analysis
             .runnables(position.file_id)
@@ -769,7 +769,7 @@ mod tests {
         expect.assert_debug_eq(&result);
     }
 
-    fn check_tests(ra_fixture: &str, expect: Expect) {
+    fn check_tests(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
         let (analysis, position) = fixture::position(ra_fixture);
         let tests = analysis.related_tests(position, None).unwrap();
         let navigation_targets = tests.into_iter().map(|runnable| runnable.nav).collect::<Vec<_>>();
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 84ccadc8c4e..f8c60418eb0 100644
--- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
@@ -692,7 +692,9 @@ mod tests {
     use crate::RootDatabase;
 
     /// Creates analysis from a multi-file fixture, returns positions marked with $0.
-    pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
+    pub(crate) fn position(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    ) -> (RootDatabase, FilePosition) {
         let change_fixture = ChangeFixture::parse(ra_fixture);
         let mut database = RootDatabase::default();
         database.apply_change(change_fixture.change);
@@ -703,7 +705,7 @@ mod tests {
     }
 
     #[track_caller]
-    fn check(ra_fixture: &str, expect: Expect) {
+    fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
         let fixture = format!(
             r#"
 //- minicore: sized, fn
diff --git a/src/tools/rust-analyzer/crates/ide/src/ssr.rs b/src/tools/rust-analyzer/crates/ide/src/ssr.rs
index 6def28e0b74..77a011cac19 100644
--- a/src/tools/rust-analyzer/crates/ide/src/ssr.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/ssr.rs
@@ -67,7 +67,10 @@ mod tests {
 
     use super::ssr_assists;
 
-    fn get_assists(ra_fixture: &str, resolve: AssistResolveStrategy) -> Vec<Assist> {
+    fn get_assists(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        resolve: AssistResolveStrategy,
+    ) -> Vec<Assist> {
         let (mut db, file_id, range_or_offset) = RootDatabase::with_range_or_offset(ra_fixture);
         let mut local_roots = FxHashSet::default();
         local_roots.insert(test_fixture::WORKSPACE);
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 700e166b238..8050a38b3ca 100644
--- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
@@ -138,6 +138,7 @@ impl StaticIndex<'_> {
                     render_colons: true,
                     discriminant_hints: crate::DiscriminantHints::Fieldless,
                     type_hints: true,
+                    sized_bound: false,
                     parameter_hints: true,
                     generic_parameter_hints: crate::GenericParameterHints {
                         type_hints: false,
@@ -290,7 +291,10 @@ mod tests {
 
     use super::VendoredLibrariesConfig;
 
-    fn check_all_ranges(ra_fixture: &str, vendored_libs_config: VendoredLibrariesConfig<'_>) {
+    fn check_all_ranges(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        vendored_libs_config: VendoredLibrariesConfig<'_>,
+    ) {
         let (analysis, ranges) = fixture::annotations_without_marker(ra_fixture);
         let s = StaticIndex::compute(&analysis, vendored_libs_config);
         let mut range_set: FxHashSet<_> = ranges.iter().map(|it| it.0).collect();
@@ -309,7 +313,10 @@ mod tests {
     }
 
     #[track_caller]
-    fn check_definitions(ra_fixture: &str, vendored_libs_config: VendoredLibrariesConfig<'_>) {
+    fn check_definitions(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        vendored_libs_config: VendoredLibrariesConfig<'_>,
+    ) {
         let (analysis, ranges) = fixture::annotations_without_marker(ra_fixture);
         let s = StaticIndex::compute(&analysis, vendored_libs_config);
         let mut range_set: FxHashSet<_> = ranges.iter().map(|it| it.0).collect();
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 4f3d5d9d00c..22a2fe4e9eb 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
@@ -386,6 +386,9 @@ pub(super) fn highlight_def(
         Definition::Field(_) | Definition::TupleField(_) => {
             Highlight::new(HlTag::Symbol(SymbolKind::Field))
         }
+        Definition::Crate(_) => {
+            Highlight::new(HlTag::Symbol(SymbolKind::Module)) | HlMod::CrateRoot
+        }
         Definition::Module(module) => {
             let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Module));
             if module.is_crate_root() {
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
index 0a157c157c3..1be90ad6a1e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
@@ -28,7 +28,14 @@ pub(super) fn ra_fixture(
     expanded: &ast::String,
 ) -> Option<()> {
     let active_parameter = ActiveParameter::at_token(sema, expanded.syntax().clone())?;
-    if !active_parameter.ident().is_some_and(|name| name.text().starts_with("ra_fixture")) {
+    let has_rust_fixture_attr = active_parameter.attrs().is_some_and(|attrs| {
+        attrs.filter_map(|attr| attr.as_simple_path()).any(|path| {
+            path.segments()
+                .zip(["rust_analyzer", "rust_fixture"])
+                .all(|(seg, name)| seg.name_ref().map_or(false, |nr| nr.text() == name))
+        })
+    });
+    if !has_rust_fixture_attr {
         return None;
     }
     let value = literal.value().ok()?;
@@ -287,7 +294,9 @@ fn find_doc_string_in_attr(attr: &hir::Attr, it: &ast::Attr) -> Option<ast::Stri
 
 fn module_def_to_hl_tag(def: Definition) -> HlTag {
     let symbol = match def {
-        Definition::Module(_) | Definition::ExternCrateDecl(_) => SymbolKind::Module,
+        Definition::Module(_) | Definition::Crate(_) | Definition::ExternCrateDecl(_) => {
+            SymbolKind::Module
+        }
         Definition::Function(_) => SymbolKind::Function,
         Definition::Adt(hir::Adt::Struct(_)) => SymbolKind::Struct,
         Definition::Adt(hir::Adt::Enum(_)) => SymbolKind::Enum,
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 cad5a8b593f..485d44f97e1 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
@@ -46,7 +46,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 </style>
 <pre><code><span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">allow</span><span class="parenthesis attribute">(</span><span class="none attribute">dead_code</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="tool_module attribute library">rustfmt</span><span class="operator attribute">::</span><span class="tool_module attribute library">skip</span><span class="attribute_bracket attribute">]</span>
+<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="tool_module attribute">rustfmt</span><span class="operator attribute">::</span><span class="tool_module attribute">skip</span><span class="attribute_bracket attribute">]</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="module attribute crate_root library">proc_macros</span><span class="operator attribute">::</span><span class="attribute attribute library">identity</span><span class="attribute_bracket attribute">]</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="attribute attribute default_library library">derive</span><span class="parenthesis attribute">(</span><span class="derive attribute default_library library">Default</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
 <span class="comment documentation">/// This is a doc comment</span>
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 edd9639768a..c6eab90e42b 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
@@ -45,7 +45,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 </style>
-<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">foo</span> <span class="brace">{</span>
+<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">foo</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span>foo<span class="colon">:</span>ident<span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">&gt;</span> <span class="brace">{</span>
         <span class="keyword">mod</span> y <span class="brace">{</span>
             <span class="keyword">pub</span> <span class="keyword">struct</span> <span class="punctuation">$</span>foo<span class="semicolon">;</span>
@@ -53,9 +53,9 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="brace">}</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="macro">foo</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="struct declaration macro public">Foo</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">foo</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="struct declaration macro public">Foo</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="keyword">mod</span> <span class="module declaration">module</span> <span class="brace">{</span>
-        <span class="macro">foo</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="struct declaration macro public">Bar</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+        <span class="macro public">foo</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="struct declaration macro public">Bar</span><span class="parenthesis macro">)</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>
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 05289cfe3fe..96cdb532dd5 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
@@ -45,7 +45,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 </style>
-<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">id</span> <span class="brace">{</span>
+<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">id</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</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>tt<span class="parenthesis">)</span><span class="punctuation">*</span>
     <span class="brace">}</span><span class="semicolon">;</span>
@@ -57,7 +57,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <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="brace">}</span>
-    <span class="macro">id</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>
+    <span class="macro public">id</span><span class="macro_bang">!</span><span class="parenthesis macro">(</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>
@@ -78,7 +78,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="keyword const">const</span> <span class="keyword">fn</span> <span class="function associated const declaration static trait">assoc_const_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="brace">}</span>
 
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">unsafe_deref</span> <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="brace">}</span><span class="semicolon">;</span>
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 aa9d23250c1..5ff96ae2a74 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
@@ -147,10 +147,10 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <span class="brace">}</span>
 
 <span class="comment documentation">/// ```</span>
-<span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">macro_rules</span><span class="macro_bang injected">!</span><span class="none injected"> </span><span class="macro declaration injected">noop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="parenthesis injected">(</span><span class="punctuation injected">$</span><span class="none injected">expr</span><span class="colon injected">:</span><span class="none injected">expr</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="operator injected">=</span><span class="operator injected">&gt;</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="punctuation injected">$</span><span class="none injected">expr </span><span class="brace injected">}</span><span class="brace injected">}</span>
-<span class="comment documentation">///</span><span class="comment documentation"> </span><span class="macro injected">noop</span><span class="macro_bang injected">!</span><span class="parenthesis injected macro">(</span><span class="numeric_literal injected macro">1</span><span class="parenthesis injected macro">)</span><span class="semicolon injected">;</span>
+<span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">macro_rules</span><span class="macro_bang injected">!</span><span class="none injected"> </span><span class="macro declaration injected public">noop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="parenthesis injected">(</span><span class="punctuation injected">$</span><span class="none injected">expr</span><span class="colon injected">:</span><span class="none injected">expr</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="operator injected">=</span><span class="operator injected">&gt;</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="punctuation injected">$</span><span class="none injected">expr </span><span class="brace injected">}</span><span class="brace injected">}</span>
+<span class="comment documentation">///</span><span class="comment documentation"> </span><span class="macro injected public">noop</span><span class="macro_bang injected">!</span><span class="parenthesis injected macro">(</span><span class="numeric_literal injected macro">1</span><span class="parenthesis injected macro">)</span><span class="semicolon injected">;</span>
 <span class="comment documentation">/// ```</span>
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">noop</span> <span class="brace">{</span>
+<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">noop</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">&gt;</span> <span class="brace">{</span>
         <span class="punctuation">$</span>expr
     <span class="brace">}</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 7820e4e5a5f..fe5f5ab6a9a 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
@@ -45,7 +45,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 </style>
-<pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="self_keyword crate_root public">self</span> <span class="keyword">as</span> <span class="module crate_root declaration">this</span><span class="semicolon">;</span>
+<pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="self_keyword crate_root">self</span> <span class="keyword">as</span> <span class="module crate_root declaration">this</span><span class="semicolon">;</span>
 <span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module crate_root default_library library">std</span><span class="semicolon">;</span>
 <span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module crate_root default_library library">alloc</span> <span class="keyword">as</span> <span class="module crate_root declaration">abc</span><span class="semicolon">;</span>
 <span class="keyword">extern</span> <span class="keyword">crate</span> <span class="unresolved_reference">unresolved</span> <span class="keyword">as</span> <span class="module crate_root declaration">definitely_unresolved</span><span class="semicolon">;</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 6c3fbcfcf41..5fbed35192b 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
@@ -45,7 +45,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 </style>
-<pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="parenthesis">(</span><span class="value_param declaration reference">ra_fixture</span><span class="colon">:</span> <span class="punctuation">&</span><span class="builtin_type">str</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
+<pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="parenthesis">(</span><span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="tool_module attribute">rust_analyzer</span><span class="operator attribute">::</span><span class="tool_module attribute">rust_fixture</span><span class="attribute_bracket attribute">]</span> <span class="value_param declaration reference">ra_fixture</span><span class="colon">:</span> <span class="punctuation">&</span><span class="builtin_type">str</span><span class="parenthesis">)</span> <span class="brace">{</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="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span><span class="none injected">
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 361dcd1bc37..06817af1b1f 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
@@ -46,8 +46,8 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 </style>
 <pre><code><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="macro">template</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">template</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">template</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">template</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 <span class="brace">}</span>
 
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="module attribute crate_root library">proc_macros</span><span class="operator attribute">::</span><span class="attribute attribute library">issue_18089</span><span class="attribute_bracket attribute">]</span>
-<span class="keyword">fn</span> <span class="macro declaration">template</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span></code></pre>
\ No newline at end of file
+<span class="keyword">fn</span> <span class="macro declaration public">template</span><span class="parenthesis">(</span><span class="parenthesis">)</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/test_data/highlight_keywords_2015.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html
index c2bf94fd9b6..2d3407dbcda 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
@@ -53,22 +53,22 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="keyword">use</span> <span class="keyword crate_root public">super</span><span class="operator">::</span><span class="punctuation">*</span><span class="semicolon">;</span>
 <span class="brace">}</span>
 
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">void</span> <span class="brace">{</span>
+<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">void</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="brace">}</span>
 
 <span class="keyword">struct</span> <span class="struct declaration">__</span> <span class="keyword">where</span> <span class="self_type_keyword">Self</span><span class="colon">:</span><span class="semicolon">;</span>
 <span class="keyword">fn</span> <span class="function declaration">__</span><span class="parenthesis">(</span><span class="punctuation">_</span><span class="colon">:</span> <span class="unresolved_reference">Self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">Self</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">Self</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 
 <span class="comment">// edition dependent</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">try</span> <span class="none macro">async</span> <span class="none macro">await</span> <span class="none macro">gen</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">try</span> <span class="none macro">async</span> <span class="none macro">await</span> <span class="none macro">gen</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 <span class="comment">// edition and context dependent</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">dyn</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">dyn</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 <span class="comment">// builtin custom syntax</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">builtin</span> <span class="none macro">offset_of</span> <span class="none macro">format_args</span> <span class="none macro">asm</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">builtin</span> <span class="none macro">offset_of</span> <span class="none macro">format_args</span> <span class="none macro">asm</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 <span class="comment">// contextual</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">macro_rules</span><span class="comma macro">,</span> <span class="none macro">union</span><span class="comma macro">,</span> <span class="none macro">default</span><span class="comma macro">,</span> <span class="none macro">raw</span><span class="comma macro">,</span> <span class="none macro">auto</span><span class="comma macro">,</span> <span class="none macro">yeet</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">macro_rules</span><span class="comma macro">,</span> <span class="none macro">union</span><span class="comma macro">,</span> <span class="none macro">default</span><span class="comma macro">,</span> <span class="none macro">raw</span><span class="comma macro">,</span> <span class="none macro">auto</span><span class="comma macro">,</span> <span class="none macro">yeet</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 <span class="comment">// reserved</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">abstract</span> <span class="keyword macro">become</span> <span class="keyword macro">box</span> <span class="keyword macro">do</span> <span class="keyword macro">final</span> <span class="keyword macro">macro</span> <span class="keyword macro">override</span> <span class="keyword macro">priv</span> <span class="keyword macro">typeof</span> <span class="keyword macro">unsized</span> <span class="keyword macro">virtual</span> <span class="keyword control macro">yield</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>'static 'self 'unsafe<span class="parenthesis macro">)</span></code></pre>
\ No newline at end of file
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">abstract</span> <span class="keyword macro">become</span> <span class="keyword macro">box</span> <span class="keyword macro">do</span> <span class="keyword macro">final</span> <span class="keyword macro">macro</span> <span class="keyword macro">override</span> <span class="keyword macro">priv</span> <span class="keyword macro">typeof</span> <span class="keyword macro">unsized</span> <span class="keyword macro">virtual</span> <span class="keyword control macro">yield</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>'static 'self 'unsafe<span class="parenthesis macro">)</span></code></pre>
\ No newline at end of file
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 a30d16d5327..f8eb5d068a8 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
@@ -53,22 +53,22 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="keyword">use</span> <span class="keyword crate_root public">super</span><span class="operator">::</span><span class="punctuation">*</span><span class="semicolon">;</span>
 <span class="brace">}</span>
 
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">void</span> <span class="brace">{</span>
+<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">void</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="brace">}</span>
 
 <span class="keyword">struct</span> <span class="struct declaration">__</span> <span class="keyword">where</span> <span class="self_type_keyword">Self</span><span class="colon">:</span><span class="semicolon">;</span>
 <span class="keyword">fn</span> <span class="function declaration">__</span><span class="parenthesis">(</span><span class="punctuation">_</span><span class="colon">:</span> <span class="unresolved_reference">Self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">Self</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">Self</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 
 <span class="comment">// edition dependent</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">try</span> <span class="keyword async macro">async</span> <span class="keyword async control macro">await</span> <span class="none macro">gen</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">try</span> <span class="keyword async macro">async</span> <span class="keyword async control macro">await</span> <span class="none macro">gen</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 <span class="comment">// edition and context dependent</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">dyn</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">dyn</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 <span class="comment">// builtin custom syntax</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">builtin</span> <span class="none macro">offset_of</span> <span class="none macro">format_args</span> <span class="none macro">asm</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">builtin</span> <span class="none macro">offset_of</span> <span class="none macro">format_args</span> <span class="none macro">asm</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 <span class="comment">// contextual</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">macro_rules</span><span class="comma macro">,</span> <span class="none macro">union</span><span class="comma macro">,</span> <span class="none macro">default</span><span class="comma macro">,</span> <span class="none macro">raw</span><span class="comma macro">,</span> <span class="none macro">auto</span><span class="comma macro">,</span> <span class="none macro">yeet</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">macro_rules</span><span class="comma macro">,</span> <span class="none macro">union</span><span class="comma macro">,</span> <span class="none macro">default</span><span class="comma macro">,</span> <span class="none macro">raw</span><span class="comma macro">,</span> <span class="none macro">auto</span><span class="comma macro">,</span> <span class="none macro">yeet</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 <span class="comment">// reserved</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">abstract</span> <span class="keyword macro">become</span> <span class="keyword macro">box</span> <span class="keyword macro">do</span> <span class="keyword macro">final</span> <span class="keyword macro">macro</span> <span class="keyword macro">override</span> <span class="keyword macro">priv</span> <span class="keyword macro">typeof</span> <span class="keyword macro">unsized</span> <span class="keyword macro">virtual</span> <span class="keyword control macro">yield</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>'static 'self 'unsafe<span class="parenthesis macro">)</span></code></pre>
\ No newline at end of file
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">abstract</span> <span class="keyword macro">become</span> <span class="keyword macro">box</span> <span class="keyword macro">do</span> <span class="keyword macro">final</span> <span class="keyword macro">macro</span> <span class="keyword macro">override</span> <span class="keyword macro">priv</span> <span class="keyword macro">typeof</span> <span class="keyword macro">unsized</span> <span class="keyword macro">virtual</span> <span class="keyword control macro">yield</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>'static 'self 'unsafe<span class="parenthesis macro">)</span></code></pre>
\ No newline at end of file
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 a30d16d5327..f8eb5d068a8 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
@@ -53,22 +53,22 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="keyword">use</span> <span class="keyword crate_root public">super</span><span class="operator">::</span><span class="punctuation">*</span><span class="semicolon">;</span>
 <span class="brace">}</span>
 
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">void</span> <span class="brace">{</span>
+<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">void</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="brace">}</span>
 
 <span class="keyword">struct</span> <span class="struct declaration">__</span> <span class="keyword">where</span> <span class="self_type_keyword">Self</span><span class="colon">:</span><span class="semicolon">;</span>
 <span class="keyword">fn</span> <span class="function declaration">__</span><span class="parenthesis">(</span><span class="punctuation">_</span><span class="colon">:</span> <span class="unresolved_reference">Self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">Self</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">Self</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 
 <span class="comment">// edition dependent</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">try</span> <span class="keyword async macro">async</span> <span class="keyword async control macro">await</span> <span class="none macro">gen</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">try</span> <span class="keyword async macro">async</span> <span class="keyword async control macro">await</span> <span class="none macro">gen</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 <span class="comment">// edition and context dependent</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">dyn</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">dyn</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 <span class="comment">// builtin custom syntax</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">builtin</span> <span class="none macro">offset_of</span> <span class="none macro">format_args</span> <span class="none macro">asm</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">builtin</span> <span class="none macro">offset_of</span> <span class="none macro">format_args</span> <span class="none macro">asm</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 <span class="comment">// contextual</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">macro_rules</span><span class="comma macro">,</span> <span class="none macro">union</span><span class="comma macro">,</span> <span class="none macro">default</span><span class="comma macro">,</span> <span class="none macro">raw</span><span class="comma macro">,</span> <span class="none macro">auto</span><span class="comma macro">,</span> <span class="none macro">yeet</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">macro_rules</span><span class="comma macro">,</span> <span class="none macro">union</span><span class="comma macro">,</span> <span class="none macro">default</span><span class="comma macro">,</span> <span class="none macro">raw</span><span class="comma macro">,</span> <span class="none macro">auto</span><span class="comma macro">,</span> <span class="none macro">yeet</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 <span class="comment">// reserved</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">abstract</span> <span class="keyword macro">become</span> <span class="keyword macro">box</span> <span class="keyword macro">do</span> <span class="keyword macro">final</span> <span class="keyword macro">macro</span> <span class="keyword macro">override</span> <span class="keyword macro">priv</span> <span class="keyword macro">typeof</span> <span class="keyword macro">unsized</span> <span class="keyword macro">virtual</span> <span class="keyword control macro">yield</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>'static 'self 'unsafe<span class="parenthesis macro">)</span></code></pre>
\ No newline at end of file
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">abstract</span> <span class="keyword macro">become</span> <span class="keyword macro">box</span> <span class="keyword macro">do</span> <span class="keyword macro">final</span> <span class="keyword macro">macro</span> <span class="keyword macro">override</span> <span class="keyword macro">priv</span> <span class="keyword macro">typeof</span> <span class="keyword macro">unsized</span> <span class="keyword macro">virtual</span> <span class="keyword control macro">yield</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>'static 'self 'unsafe<span class="parenthesis macro">)</span></code></pre>
\ No newline at end of file
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 b82a3f9f819..fca84017069 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
@@ -53,22 +53,22 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="keyword">use</span> <span class="keyword crate_root public">super</span><span class="operator">::</span><span class="punctuation">*</span><span class="semicolon">;</span>
 <span class="brace">}</span>
 
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">void</span> <span class="brace">{</span>
+<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">void</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="brace">}</span>
 
 <span class="keyword">struct</span> <span class="struct declaration">__</span> <span class="keyword">where</span> <span class="self_type_keyword">Self</span><span class="colon">:</span><span class="semicolon">;</span>
 <span class="keyword">fn</span> <span class="function declaration">__</span><span class="parenthesis">(</span><span class="punctuation">_</span><span class="colon">:</span> <span class="unresolved_reference">Self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">Self</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">Self</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 
 <span class="comment">// edition dependent</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">try</span> <span class="keyword async macro">async</span> <span class="keyword async control macro">await</span> <span class="keyword macro">gen</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">try</span> <span class="keyword async macro">async</span> <span class="keyword async control macro">await</span> <span class="keyword macro">gen</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 <span class="comment">// edition and context dependent</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">dyn</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">dyn</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 <span class="comment">// builtin custom syntax</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">builtin</span> <span class="none macro">offset_of</span> <span class="none macro">format_args</span> <span class="none macro">asm</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">builtin</span> <span class="none macro">offset_of</span> <span class="none macro">format_args</span> <span class="none macro">asm</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 <span class="comment">// contextual</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">macro_rules</span><span class="comma macro">,</span> <span class="none macro">union</span><span class="comma macro">,</span> <span class="none macro">default</span><span class="comma macro">,</span> <span class="none macro">raw</span><span class="comma macro">,</span> <span class="none macro">auto</span><span class="comma macro">,</span> <span class="none macro">yeet</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">macro_rules</span><span class="comma macro">,</span> <span class="none macro">union</span><span class="comma macro">,</span> <span class="none macro">default</span><span class="comma macro">,</span> <span class="none macro">raw</span><span class="comma macro">,</span> <span class="none macro">auto</span><span class="comma macro">,</span> <span class="none macro">yeet</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 <span class="comment">// reserved</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">abstract</span> <span class="keyword macro">become</span> <span class="keyword macro">box</span> <span class="keyword macro">do</span> <span class="keyword macro">final</span> <span class="keyword macro">macro</span> <span class="keyword macro">override</span> <span class="keyword macro">priv</span> <span class="keyword macro">typeof</span> <span class="keyword macro">unsized</span> <span class="keyword macro">virtual</span> <span class="keyword control macro">yield</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>'static 'self 'unsafe<span class="parenthesis macro">)</span></code></pre>
\ No newline at end of file
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">abstract</span> <span class="keyword macro">become</span> <span class="keyword macro">box</span> <span class="keyword macro">do</span> <span class="keyword macro">final</span> <span class="keyword macro">macro</span> <span class="keyword macro">override</span> <span class="keyword macro">priv</span> <span class="keyword macro">typeof</span> <span class="keyword macro">unsized</span> <span class="keyword macro">virtual</span> <span class="keyword control macro">yield</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>'static 'self 'unsafe<span class="parenthesis macro">)</span></code></pre>
\ No newline at end of file
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 06673d1a73c..f640a5e6ca7 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
@@ -53,34 +53,34 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
         <span class="comma macro proc_macro">,</span><span class="builtin_type macro proc_macro">i32</span> <span class="colon macro proc_macro">:</span><span class="field declaration macro proc_macro public">y</span> <span class="keyword macro proc_macro">pub</span>
     <span class="brace macro proc_macro">}</span> <span class="struct declaration macro proc_macro">Foo</span> <span class="keyword macro proc_macro">struct</span>
 <span class="brace macro proc_macro">}</span>
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">def_fn</span> <span class="brace">{</span>
+<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">def_fn</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</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>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="brace">}</span>
 <span class="brace">}</span>
 
-<span class="macro">def_fn</span><span class="macro_bang">!</span> <span class="brace macro">{</span>
+<span class="macro public">def_fn</span><span class="macro_bang">!</span> <span class="brace macro">{</span>
     <span class="keyword macro">fn</span> <span class="function declaration macro">bar</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span> <span class="operator macro">-</span><span class="operator macro">&gt;</span> <span class="builtin_type macro">u32</span> <span class="brace macro">{</span>
         <span class="numeric_literal macro">100</span>
     <span class="brace macro">}</span>
 <span class="brace macro">}</span>
 
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">dont_color_me_braces</span> <span class="brace">{</span>
+<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">dont_color_me_braces</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="numeric_literal">0</span><span class="brace">}</span>
 <span class="brace">}</span>
 
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">noop</span> <span class="brace">{</span>
+<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">noop</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">&gt;</span> <span class="brace">{</span>
         <span class="punctuation">$</span>expr
     <span class="brace">}</span>
 <span class="brace">}</span>
 
 <span class="comment documentation">/// textually shadow previous definition</span>
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">noop</span> <span class="brace">{</span>
+<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">noop</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">&gt;</span> <span class="brace">{</span>
         <span class="punctuation">$</span>expr
     <span class="brace">}</span>
 <span class="brace">}</span>
 
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">keyword_frag</span> <span class="brace">{</span>
+<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">keyword_frag</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="colon">:</span>ty<span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">&gt;</span> <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="parenthesis">)</span>
 <span class="brace">}</span>
 
@@ -94,7 +94,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="brace">}</span>
 <span class="brace">}</span>
 
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">id</span> <span class="brace">{</span>
+<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">id</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</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>tt<span class="parenthesis">)</span><span class="punctuation">*</span>
     <span class="brace">}</span><span class="semicolon">;</span>
@@ -106,10 +106,10 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <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">struct</span> <span class="struct declaration">TestLocal</span><span class="semicolon">;</span>
     <span class="comment">// regression test, TestLocal here used to not resolve</span>
-    <span class="keyword">let</span> <span class="punctuation">_</span><span class="colon">:</span> <span class="struct">S</span><span class="angle">&lt;</span><span class="macro">id</span><span class="macro_bang">!</span><span class="bracket macro">[</span><span class="struct macro">TestLocal</span><span class="bracket macro">]</span><span class="angle">&gt;</span><span class="semicolon">;</span>
+    <span class="keyword">let</span> <span class="punctuation">_</span><span class="colon">:</span> <span class="struct">S</span><span class="angle">&lt;</span><span class="macro public">id</span><span class="macro_bang">!</span><span class="bracket macro">[</span><span class="struct macro">TestLocal</span><span class="bracket macro">]</span><span class="angle">&gt;</span><span class="semicolon">;</span>
 
     <span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="parenthesis macro">(</span><span class="numeric_literal macro">92</span><span class="comma macro">,</span><span class="parenthesis macro">)</span><span class="operator macro">.</span><span class="field library macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">dont_color_me_braces</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">noop</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="macro macro">noop</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">dont_color_me_braces</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">noop</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="macro macro public">noop</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</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_strings.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
index 1385ae0510a..0a7e273950d 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
@@ -45,14 +45,14 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 </style>
-<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">println</span> <span class="brace">{</span>
+<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">println</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">&gt;</span> <span class="parenthesis">(</span><span class="brace">{</span>
         <span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>io<span class="colon">:</span><span class="colon">:</span>_print<span class="parenthesis">(</span>format_args_nl<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
     <span class="brace">}</span><span class="parenthesis">)</span>
 <span class="brace">}</span>
 
 <span class="keyword">mod</span> <span class="module declaration">panic</span> <span class="brace">{</span>
-    <span class="keyword">pub</span> <span class="keyword">macro</span> <span class="macro declaration">panic_2015</span> <span class="brace">{</span>
+    <span class="keyword">pub</span> <span class="keyword">macro</span> <span class="macro declaration public">panic_2015</span> <span class="brace">{</span>
         <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span>
             panic<span class="parenthesis">(</span><span class="string_literal">"explicit panic"</span><span class="parenthesis">)</span>
         <span class="parenthesis">)</span><span class="comma">,</span>
@@ -73,12 +73,12 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="brace">}</span>
 <span class="brace">}</span>
 
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">toho</span> <span class="brace">{</span>
+<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">toho</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">&gt;</span> <span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panic<span class="punctuation">!</span><span class="parenthesis">(</span><span class="string_literal">"not yet implemented"</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">&gt;</span> <span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panic<span class="punctuation">!</span><span class="parenthesis">(</span><span class="string_literal">"not yet implemented: {}"</span><span class="comma">,</span> format_args<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
 <span class="brace">}</span>
 
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">reuse_twice</span> <span class="brace">{</span>
+<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">reuse_twice</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span>literal<span class="colon">:</span>literal<span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">&gt;</span> <span class="brace">{</span><span class="brace">{</span>stringify<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span>literal<span class="parenthesis">)</span><span class="semicolon">;</span> format_args<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span>literal<span class="parenthesis">)</span><span class="brace">}</span><span class="brace">}</span><span class="semicolon">;</span>
 <span class="brace">}</span>
 
@@ -95,74 +95,74 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
     <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="byte_literal">b'</span><span class="escape_sequence">\xFF</span><span class="byte_literal">'</span><span class="semicolon">;</span>
 
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="escape_sequence">{{</span><span class="string_literal macro">Hello</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="escape_sequence">{{</span><span class="string_literal macro">Hello</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="comment">// from https://doc.rust-lang.org/std/fmt/index.html</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>                 <span class="comment">// =&gt; "Hello"</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"world"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>   <span class="comment">// =&gt; "Hello, world!"</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"The number is </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>   <span class="comment">// =&gt; "The number is 1"</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="parenthesis macro">(</span><span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="numeric_literal macro">4</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>          <span class="comment">// =&gt; "(3, 4)"</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">value</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">value</span><span class="operator macro">=</span><span class="numeric_literal macro">4</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>      <span class="comment">// =&gt; "4"</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>           <span class="comment">// =&gt; "1 2"</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">4</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">42</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>             <span class="comment">// =&gt; "0042" with leading zerosV</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>   <span class="comment">// =&gt; "2 1 1 2"</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">argument</span> <span class="operator macro">=</span> <span class="string_literal macro">"test"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>   <span class="comment">// =&gt; "test"</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span> <span class="operator macro">=</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>          <span class="comment">// =&gt; "2 1"</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">a</span><span class="operator macro">=</span><span class="string_literal macro">"a"</span><span class="comma macro">,</span> <span class="variable declaration macro">b</span><span class="operator macro">=</span><span class="char_literal macro">'b'</span><span class="comma macro">,</span> <span class="variable declaration macro">c</span><span class="operator macro">=</span><span class="numeric_literal macro">3</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>  <span class="comment">// =&gt; "a 3 b"</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>                       <span class="comment">// =&gt; "{2}"</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">width</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="variable declaration macro">width</span> <span class="operator macro">=</span> <span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">&lt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">-</span><span class="format_specifier">&lt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">+</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">27</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">-</span><span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="numeric_literal">0</span><span class="numeric_literal">10</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">27</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span>    <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span>   <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="variable">number</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="variable">prec</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="variable declaration macro">prec</span> <span class="operator macro">=</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="variable declaration macro">number</span> <span class="operator macro">=</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 fractional digits"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span><span class="operator macro">=</span><span class="numeric_literal macro">1234.56</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 characters"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span><span class="operator macro">=</span><span class="string_literal macro">"1234.56"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">8</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 right-aligned characters"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span><span class="operator macro">=</span><span class="string_literal macro">"1234.56"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>                 <span class="comment">// =&gt; "Hello"</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"world"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>   <span class="comment">// =&gt; "Hello, world!"</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"The number is </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>   <span class="comment">// =&gt; "The number is 1"</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="parenthesis macro">(</span><span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="numeric_literal macro">4</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>          <span class="comment">// =&gt; "(3, 4)"</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">value</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">value</span><span class="operator macro">=</span><span class="numeric_literal macro">4</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>      <span class="comment">// =&gt; "4"</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>           <span class="comment">// =&gt; "1 2"</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">4</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">42</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>             <span class="comment">// =&gt; "0042" with leading zerosV</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>   <span class="comment">// =&gt; "2 1 1 2"</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">argument</span> <span class="operator macro">=</span> <span class="string_literal macro">"test"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>   <span class="comment">// =&gt; "test"</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span> <span class="operator macro">=</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>          <span class="comment">// =&gt; "2 1"</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">a</span><span class="operator macro">=</span><span class="string_literal macro">"a"</span><span class="comma macro">,</span> <span class="variable declaration macro">b</span><span class="operator macro">=</span><span class="char_literal macro">'b'</span><span class="comma macro">,</span> <span class="variable declaration macro">c</span><span class="operator macro">=</span><span class="numeric_literal macro">3</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>  <span class="comment">// =&gt; "a 3 b"</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>                       <span class="comment">// =&gt; "{2}"</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">width</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="variable declaration macro">width</span> <span class="operator macro">=</span> <span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">&lt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">-</span><span class="format_specifier">&lt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">+</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">27</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">-</span><span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="numeric_literal">0</span><span class="numeric_literal">10</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">27</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span>    <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span>   <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="variable">number</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="variable">prec</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="variable declaration macro">prec</span> <span class="operator macro">=</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="variable declaration macro">number</span> <span class="operator macro">=</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 fractional digits"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span><span class="operator macro">=</span><span class="numeric_literal macro">1234.56</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 characters"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span><span class="operator macro">=</span><span class="string_literal macro">"1234.56"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">8</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 right-aligned characters"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span><span class="operator macro">=</span><span class="string_literal macro">"1234.56"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 
     <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">"{}"</span>
     <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">"{{}}"</span><span class="semicolon">;</span>
 
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="escape_sequence">{{</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="string_literal macro"> Hello"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="string_literal macro">Hello</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="string_literal macro"> Hello </span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="string_literal macro">Hello </span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="string_literal macro"> Hello</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="escape_sequence">{{</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="string_literal macro"> Hello"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="string_literal macro">Hello</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="string_literal macro"> Hello </span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="string_literal macro">Hello </span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="string_literal macro"> Hello</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">r"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"world"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">r"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"world"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 
     <span class="comment">// escape sequences</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello</span><span class="escape_sequence">\n</span><span class="string_literal macro">World"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">\u{48}</span><span class="escape_sequence">\x65</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6F</span><span class="string_literal macro"> World"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello</span><span class="escape_sequence">\n</span><span class="string_literal macro">World"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">\u{48}</span><span class="escape_sequence">\x65</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6F</span><span class="string_literal macro"> World"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 
     <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">"</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x00</span><span class="escape_sequence">\x63</span><span class="invalid_escape_sequence">\xFF</span><span class="escape_sequence">\u{FF}</span><span class="escape_sequence">\n</span><span class="string_literal">"</span><span class="semicolon">;</span> <span class="comment">// invalid non-UTF8 escape sequences</span>
     <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">b"</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x00</span><span class="escape_sequence">\x63</span><span class="escape_sequence">\xFF</span><span class="invalid_escape_sequence">\u{FF}</span><span class="escape_sequence">\n</span><span class="string_literal">"</span><span class="semicolon">;</span> <span class="comment">// valid bytes, invalid unicodes</span>
     <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">c"</span><span class="escape_sequence">\u{FF}</span><span class="escape_sequence">\xFF</span><span class="string_literal">"</span><span class="semicolon">;</span> <span class="comment">// valid bytes, valid unicodes</span>
     <span class="keyword">let</span> <span class="variable declaration reference">backslash</span> <span class="operator">=</span> <span class="string_literal">r"\\"</span><span class="semicolon">;</span>
 
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">A</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">ничоси</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">A</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">ничоси</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">x</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> "</span><span class="comma macro">,</span> <span class="unresolved_reference macro">thingy</span><span class="comma macro">,</span> <span class="unresolved_reference macro">n2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">x</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> "</span><span class="comma macro">,</span> <span class="unresolved_reference macro">thingy</span><span class="comma macro">,</span> <span class="unresolved_reference macro">n2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="macro default_library library">panic</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"{}"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="macro default_library library">panic</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"more </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="macro default_library library">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma macro">,</span> <span class="string_literal macro">"{}"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="macro default_library library">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma macro">,</span> <span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> asdasd"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">toho</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"{}fmt"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">toho</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"{}fmt"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</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 macro">(</span>
@@ -175,6 +175,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <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>
     <span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis 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">"{}"</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="string_literal macro">"{}"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">backslash</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">CONSTANT</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">m</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="comma macro">,</span> <span class="macro default_library library macro">format_args</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="unresolved_reference macro">foo</span><span class="comma macro">,</span> <span class="string_literal macro">"bar"</span><span class="comma macro">,</span> <span class="macro macro">toho</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">reuse_twice</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">backslash</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">backslash</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">CONSTANT</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">m</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="comma macro">,</span> <span class="macro default_library library macro">format_args</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="unresolved_reference macro">foo</span><span class="comma macro">,</span> <span class="string_literal macro">"bar"</span><span class="comma macro">,</span> <span class="macro macro public">toho</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro public">reuse_twice</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">backslash</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</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_unsafe.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index 4e69c82f3da..d9beac30898 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
@@ -45,12 +45,12 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 </style>
-<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">id</span> <span class="brace">{</span>
+<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">id</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</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>tt<span class="parenthesis">)</span><span class="punctuation">*</span>
     <span class="brace">}</span><span class="semicolon">;</span>
 <span class="brace">}</span>
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">unsafe_deref</span> <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="brace">}</span><span class="semicolon">;</span>
@@ -92,13 +92,13 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <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="macro">id</span><span class="macro_bang">!</span> <span class="brace macro">{</span>
-        <span class="keyword macro unsafe">unsafe</span> <span class="brace macro">{</span> <span class="macro macro 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="macro public">id</span><span class="macro_bang">!</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">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span> <span class="brace macro">}</span>
     <span class="brace macro">}</span><span class="semicolon">;</span>
 
     <span class="keyword unsafe">unsafe</span> <span class="brace">{</span>
-        <span class="macro unsafe">unsafe_deref</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-        <span class="macro unsafe">id</span><span class="macro_bang">!</span> <span class="brace macro">{</span> <span class="macro macro 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="semicolon">;</span>
+        <span class="macro public unsafe">unsafe_deref</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+        <span class="macro public unsafe">id</span><span class="macro_bang">!</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="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>
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 a20147add36..af52b33de64 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
@@ -990,7 +990,7 @@ impl t for foo {
 fn test_injection() {
     check_highlighting(
         r##"
-fn fixture(ra_fixture: &str) {}
+fn fixture(#[rust_analyzer::rust_fixture] ra_fixture: &str) {}
 
 fn main() {
     fixture(r#"
@@ -1188,7 +1188,11 @@ fn foo(x: &fn(&dyn Trait)) {}
 /// Highlights the code given by the `ra_fixture` argument, renders the
 /// result as HTML, and compares it with the HTML file given as `snapshot`.
 /// Note that the `snapshot` file is overwritten by the rendered HTML.
-fn check_highlighting(ra_fixture: &str, expect: ExpectFile, rainbow: bool) {
+fn check_highlighting(
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    expect: ExpectFile,
+    rainbow: bool,
+) {
     let (analysis, file_id) = fixture::file(ra_fixture.trim());
     let actual_html = &analysis.highlight_as_html(file_id, rainbow).unwrap();
     expect.assert_eq(actual_html)
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs
deleted file mode 100644
index e241cb82bd5..00000000000
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs
+++ /dev/null
@@ -1,338 +0,0 @@
-use hir::Semantics;
-use ide_db::{FileId, RootDatabase};
-use syntax::{
-    AstNode, NodeOrToken, SourceFile, SyntaxKind::STRING, SyntaxToken, TextRange, TextSize,
-};
-
-// Feature: Show Syntax Tree
-//
-// Shows the parse tree of the current file. It exists mostly for debugging
-// rust-analyzer itself.
-//
-// |===
-// | Editor  | Action Name
-//
-// | VS Code | **rust-analyzer: Show Syntax Tree**
-// |===
-// image::https://user-images.githubusercontent.com/48062697/113065586-068bdb80-91b1-11eb-9507-fee67f9f45a0.gif[]
-pub(crate) fn syntax_tree(
-    db: &RootDatabase,
-    file_id: FileId,
-    text_range: Option<TextRange>,
-) -> String {
-    let sema = Semantics::new(db);
-    let parse = sema.parse_guess_edition(file_id);
-    if let Some(text_range) = text_range {
-        let node = match parse.syntax().covering_element(text_range) {
-            NodeOrToken::Node(node) => node,
-            NodeOrToken::Token(token) => {
-                if let Some(tree) = syntax_tree_for_string(&token, text_range) {
-                    return tree;
-                }
-                token.parent().unwrap()
-            }
-        };
-
-        format!("{node:#?}")
-    } else {
-        format!("{:#?}", parse.syntax())
-    }
-}
-
-/// Attempts parsing the selected contents of a string literal
-/// as rust syntax and returns its syntax tree
-fn syntax_tree_for_string(token: &SyntaxToken, text_range: TextRange) -> Option<String> {
-    // When the range is inside a string
-    // we'll attempt parsing it as rust syntax
-    // to provide the syntax tree of the contents of the string
-    match token.kind() {
-        STRING => syntax_tree_for_token(token, text_range),
-        _ => None,
-    }
-}
-
-fn syntax_tree_for_token(node: &SyntaxToken, text_range: TextRange) -> Option<String> {
-    // Range of the full node
-    let node_range = node.text_range();
-    let text = node.text().to_owned();
-
-    // We start at some point inside the node
-    // Either we have selected the whole string
-    // or our selection is inside it
-    let start = text_range.start() - node_range.start();
-
-    // how many characters we have selected
-    let len = text_range.len();
-
-    let node_len = node_range.len();
-
-    // We want to cap our length
-    let len = len.min(node_len);
-
-    // Ensure our slice is inside the actual string
-    let end =
-        if start + len < TextSize::of(&text) { start + len } else { TextSize::of(&text) - start };
-
-    let text = &text[TextRange::new(start, end)];
-
-    // Remove possible extra string quotes from the start
-    // and the end of the string
-    let text = text
-        .trim_start_matches('r')
-        .trim_start_matches('#')
-        .trim_start_matches('"')
-        .trim_end_matches('#')
-        .trim_end_matches('"')
-        .trim()
-        // Remove custom markers
-        .replace("$0", "");
-
-    let parsed = SourceFile::parse(&text, span::Edition::CURRENT_FIXME);
-
-    // If the "file" parsed without errors,
-    // return its syntax
-    if parsed.errors().is_empty() {
-        return Some(format!("{:#?}", parsed.tree().syntax()));
-    }
-
-    None
-}
-
-#[cfg(test)]
-mod tests {
-    use expect_test::expect;
-
-    use crate::fixture;
-
-    fn check(ra_fixture: &str, expect: expect_test::Expect) {
-        let (analysis, file_id) = fixture::file(ra_fixture);
-        let syn = analysis.syntax_tree(file_id, None).unwrap();
-        expect.assert_eq(&syn)
-    }
-    fn check_range(ra_fixture: &str, expect: expect_test::Expect) {
-        let (analysis, frange) = fixture::range(ra_fixture);
-        let syn = analysis.syntax_tree(frange.file_id, Some(frange.range)).unwrap();
-        expect.assert_eq(&syn)
-    }
-
-    #[test]
-    fn test_syntax_tree_without_range() {
-        // Basic syntax
-        check(
-            r#"fn foo() {}"#,
-            expect![[r#"
-                SOURCE_FILE@0..11
-                  FN@0..11
-                    FN_KW@0..2 "fn"
-                    WHITESPACE@2..3 " "
-                    NAME@3..6
-                      IDENT@3..6 "foo"
-                    PARAM_LIST@6..8
-                      L_PAREN@6..7 "("
-                      R_PAREN@7..8 ")"
-                    WHITESPACE@8..9 " "
-                    BLOCK_EXPR@9..11
-                      STMT_LIST@9..11
-                        L_CURLY@9..10 "{"
-                        R_CURLY@10..11 "}"
-            "#]],
-        );
-
-        check(
-            r#"
-fn test() {
-    assert!("
-    fn foo() {
-    }
-    ", "");
-}"#,
-            expect![[r#"
-                SOURCE_FILE@0..60
-                  FN@0..60
-                    FN_KW@0..2 "fn"
-                    WHITESPACE@2..3 " "
-                    NAME@3..7
-                      IDENT@3..7 "test"
-                    PARAM_LIST@7..9
-                      L_PAREN@7..8 "("
-                      R_PAREN@8..9 ")"
-                    WHITESPACE@9..10 " "
-                    BLOCK_EXPR@10..60
-                      STMT_LIST@10..60
-                        L_CURLY@10..11 "{"
-                        WHITESPACE@11..16 "\n    "
-                        EXPR_STMT@16..58
-                          MACRO_EXPR@16..57
-                            MACRO_CALL@16..57
-                              PATH@16..22
-                                PATH_SEGMENT@16..22
-                                  NAME_REF@16..22
-                                    IDENT@16..22 "assert"
-                              BANG@22..23 "!"
-                              TOKEN_TREE@23..57
-                                L_PAREN@23..24 "("
-                                STRING@24..52 "\"\n    fn foo() {\n     ..."
-                                COMMA@52..53 ","
-                                WHITESPACE@53..54 " "
-                                STRING@54..56 "\"\""
-                                R_PAREN@56..57 ")"
-                          SEMICOLON@57..58 ";"
-                        WHITESPACE@58..59 "\n"
-                        R_CURLY@59..60 "}"
-            "#]],
-        )
-    }
-
-    #[test]
-    fn test_syntax_tree_with_range() {
-        check_range(
-            r#"$0fn foo() {}$0"#,
-            expect![[r#"
-                FN@0..11
-                  FN_KW@0..2 "fn"
-                  WHITESPACE@2..3 " "
-                  NAME@3..6
-                    IDENT@3..6 "foo"
-                  PARAM_LIST@6..8
-                    L_PAREN@6..7 "("
-                    R_PAREN@7..8 ")"
-                  WHITESPACE@8..9 " "
-                  BLOCK_EXPR@9..11
-                    STMT_LIST@9..11
-                      L_CURLY@9..10 "{"
-                      R_CURLY@10..11 "}"
-            "#]],
-        );
-
-        check_range(
-            r#"
-fn test() {
-    $0assert!("
-    fn foo() {
-    }
-    ", "");$0
-}"#,
-            expect![[r#"
-                EXPR_STMT@16..58
-                  MACRO_EXPR@16..57
-                    MACRO_CALL@16..57
-                      PATH@16..22
-                        PATH_SEGMENT@16..22
-                          NAME_REF@16..22
-                            IDENT@16..22 "assert"
-                      BANG@22..23 "!"
-                      TOKEN_TREE@23..57
-                        L_PAREN@23..24 "("
-                        STRING@24..52 "\"\n    fn foo() {\n     ..."
-                        COMMA@52..53 ","
-                        WHITESPACE@53..54 " "
-                        STRING@54..56 "\"\""
-                        R_PAREN@56..57 ")"
-                  SEMICOLON@57..58 ";"
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_syntax_tree_inside_string() {
-        check_range(
-            r#"fn test() {
-    assert!("
-$0fn foo() {
-}$0
-fn bar() {
-}
-    ", "");
-}"#,
-            expect![[r#"
-                SOURCE_FILE@0..12
-                  FN@0..12
-                    FN_KW@0..2 "fn"
-                    WHITESPACE@2..3 " "
-                    NAME@3..6
-                      IDENT@3..6 "foo"
-                    PARAM_LIST@6..8
-                      L_PAREN@6..7 "("
-                      R_PAREN@7..8 ")"
-                    WHITESPACE@8..9 " "
-                    BLOCK_EXPR@9..12
-                      STMT_LIST@9..12
-                        L_CURLY@9..10 "{"
-                        WHITESPACE@10..11 "\n"
-                        R_CURLY@11..12 "}"
-            "#]],
-        );
-
-        // With a raw string
-        check_range(
-            r###"fn test() {
-    assert!(r#"
-$0fn foo() {
-}$0
-fn bar() {
-}
-    "#, "");
-}"###,
-            expect![[r#"
-                SOURCE_FILE@0..12
-                  FN@0..12
-                    FN_KW@0..2 "fn"
-                    WHITESPACE@2..3 " "
-                    NAME@3..6
-                      IDENT@3..6 "foo"
-                    PARAM_LIST@6..8
-                      L_PAREN@6..7 "("
-                      R_PAREN@7..8 ")"
-                    WHITESPACE@8..9 " "
-                    BLOCK_EXPR@9..12
-                      STMT_LIST@9..12
-                        L_CURLY@9..10 "{"
-                        WHITESPACE@10..11 "\n"
-                        R_CURLY@11..12 "}"
-            "#]],
-        );
-
-        // With a raw string
-        check_range(
-            r###"fn test() {
-    assert!(r$0#"
-fn foo() {
-}
-fn bar() {
-}"$0#, "");
-}"###,
-            expect![[r#"
-                SOURCE_FILE@0..25
-                  FN@0..12
-                    FN_KW@0..2 "fn"
-                    WHITESPACE@2..3 " "
-                    NAME@3..6
-                      IDENT@3..6 "foo"
-                    PARAM_LIST@6..8
-                      L_PAREN@6..7 "("
-                      R_PAREN@7..8 ")"
-                    WHITESPACE@8..9 " "
-                    BLOCK_EXPR@9..12
-                      STMT_LIST@9..12
-                        L_CURLY@9..10 "{"
-                        WHITESPACE@10..11 "\n"
-                        R_CURLY@11..12 "}"
-                  WHITESPACE@12..13 "\n"
-                  FN@13..25
-                    FN_KW@13..15 "fn"
-                    WHITESPACE@15..16 " "
-                    NAME@16..19
-                      IDENT@16..19 "bar"
-                    PARAM_LIST@19..21
-                      L_PAREN@19..20 "("
-                      R_PAREN@20..21 ")"
-                    WHITESPACE@21..22 " "
-                    BLOCK_EXPR@22..25
-                      STMT_LIST@22..25
-                        L_CURLY@22..23 "{"
-                        WHITESPACE@23..24 "\n"
-                        R_CURLY@24..25 "}"
-            "#]],
-        );
-    }
-}
diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs
index 8998934e0e8..47d75f1c957 100644
--- a/src/tools/rust-analyzer/crates/ide/src/typing.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs
@@ -436,14 +436,18 @@ mod tests {
         })
     }
 
-    fn type_char(char_typed: char, ra_fixture_before: &str, ra_fixture_after: &str) {
+    fn type_char(
+        char_typed: char,
+        #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+        #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
+    ) {
         let actual = do_type_char(char_typed, ra_fixture_before)
             .unwrap_or_else(|| panic!("typing `{char_typed}` did nothing"));
 
         assert_eq_text!(ra_fixture_after, &actual);
     }
 
-    fn type_char_noop(char_typed: char, ra_fixture_before: &str) {
+    fn type_char_noop(char_typed: char, #[rust_analyzer::rust_fixture] ra_fixture_before: &str) {
         let file_change = do_type_char(char_typed, ra_fixture_before);
         assert_eq!(file_change, None)
     }
@@ -889,7 +893,7 @@ fn main() {
         type_char_noop(
             '{',
             r##"
-fn check_with(ra_fixture: &str, expect: Expect) {
+fn check_with(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let base = r#"
 enum E { T(), R$0, C }
 use self::E::X;
@@ -1191,7 +1195,7 @@ fn f(n: a<>b::<d>::c) {}
         type_char_noop(
             '(',
             r##"
-fn check_with(ra_fixture: &str, expect: Expect) {
+fn check_with(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let base = r#"
 enum E { T(), R$0, C }
 use self::E::X;
diff --git a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
index 773e352220e..e249c38c73d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
@@ -208,7 +208,10 @@ mod tests {
         Some(actual)
     }
 
-    fn do_check(ra_fixture_before: &str, ra_fixture_after: &str) {
+    fn do_check(
+        #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+        #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
+    ) {
         let ra_fixture_after = &trim_indent(ra_fixture_after);
         let actual = apply_on_enter(ra_fixture_before).unwrap();
         assert_eq_text!(ra_fixture_after, &actual);
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 830c39e21ea..ff74e05e943 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
@@ -220,7 +220,9 @@ mod tests {
     use crate::fixture;
     use expect_test::expect;
 
-    fn make_memory_layout(ra_fixture: &str) -> Option<RecursiveMemoryLayout> {
+    fn make_memory_layout(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    ) -> Option<RecursiveMemoryLayout> {
         let (analysis, position, _) = fixture::annotations(ra_fixture);
 
         view_memory_layout(&analysis.db, position)
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_syntax_tree.rs b/src/tools/rust-analyzer/crates/ide/src/view_syntax_tree.rs
new file mode 100644
index 00000000000..218ee15a7dd
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide/src/view_syntax_tree.rs
@@ -0,0 +1,226 @@
+use hir::Semantics;
+use ide_db::{FileId, RootDatabase};
+use span::TextRange;
+use stdx::format_to;
+use syntax::{
+    ast::{self, IsString},
+    AstNode, AstToken, NodeOrToken, SourceFile, SyntaxNode, SyntaxToken, WalkEvent,
+};
+
+// Feature: Show Syntax Tree
+//
+// Shows a tree view with the syntax tree of the current file
+//
+// |===
+// | Editor  | Panel Name
+//
+// | VS Code | **Rust Syntax Tree**
+// |===
+pub(crate) fn view_syntax_tree(db: &RootDatabase, file_id: FileId) -> String {
+    let sema = Semantics::new(db);
+    let parse = sema.parse_guess_edition(file_id);
+    syntax_node_to_json(parse.syntax(), None)
+}
+
+fn syntax_node_to_json(node: &SyntaxNode, ctx: Option<InStringCtx>) -> String {
+    let mut result = String::new();
+    for event in node.preorder_with_tokens() {
+        match event {
+            WalkEvent::Enter(it) => {
+                let kind = it.kind();
+                let (text_range, inner_range_str) = match &ctx {
+                    Some(ctx) => {
+                        let inner_start: u32 = it.text_range().start().into();
+                        let inner_end: u32 = it.text_range().end().into();
+
+                        let mut true_start = inner_start + ctx.offset;
+                        let mut true_end = inner_end + ctx.offset;
+                        for pos in &ctx.marker_positions {
+                            if *pos >= inner_end {
+                                break;
+                            }
+
+                            // We conditionally add to true_start in case
+                            // the marker is between the start and end.
+                            true_start += 2 * (*pos < inner_start) as u32;
+                            true_end += 2;
+                        }
+
+                        let true_range = TextRange::new(true_start.into(), true_end.into());
+
+                        (
+                            true_range,
+                            format!(
+                                r#","istart":{:?},"iend":{:?}"#,
+                                it.text_range().start(),
+                                it.text_range().end()
+                            ),
+                        )
+                    }
+                    None => (it.text_range(), "".to_owned()),
+                };
+                let start = text_range.start();
+                let end = text_range.end();
+
+                match it {
+                    NodeOrToken::Node(_) => {
+                        format_to!(
+                            result,
+                            r#"{{"type":"Node","kind":"{kind:?}","start":{start:?},"end":{end:?}{inner_range_str},"children":["#
+                        );
+                    }
+                    NodeOrToken::Token(token) => {
+                        let comma = if token.next_sibling_or_token().is_some() { "," } else { "" };
+                        match parse_rust_string(token) {
+                            Some(parsed) => {
+                                format_to!(
+                                    result,
+                                    r#"{{"type":"Node","kind":"{kind:?}","start":{start:?},"end":{end:?}{inner_range_str},"children":[{parsed}]}}{comma}"#
+                                );
+                            }
+                            None => format_to!(
+                                result,
+                                r#"{{"type":"Token","kind":"{kind:?}","start":{start:?},"end":{end:?}{inner_range_str}}}{comma}"#
+                            ),
+                        }
+                    }
+                }
+            }
+            WalkEvent::Leave(it) => match it {
+                NodeOrToken::Node(node) => {
+                    let comma = if node.next_sibling_or_token().is_some() { "," } else { "" };
+                    format_to!(result, "]}}{comma}")
+                }
+                NodeOrToken::Token(_) => (),
+            },
+        }
+    }
+
+    result
+}
+
+fn parse_rust_string(token: SyntaxToken) -> Option<String> {
+    let string_node = ast::String::cast(token)?;
+    let text = string_node.value().ok()?;
+
+    let mut trim_result = String::new();
+    let mut marker_positions = Vec::new();
+    let mut skipped = 0;
+    let mut last_end = 0;
+    for (start, part) in text.match_indices("$0") {
+        marker_positions.push((start - skipped) as u32);
+        trim_result.push_str(&text[last_end..start]);
+        skipped += part.len();
+        last_end = start + part.len();
+    }
+    trim_result.push_str(&text[last_end..text.len()]);
+
+    let parsed = SourceFile::parse(&trim_result, span::Edition::CURRENT);
+
+    if !parsed.errors().is_empty() {
+        return None;
+    }
+
+    let node: &SyntaxNode = &parsed.syntax_node();
+
+    if node.children().count() == 0 {
+        // C'mon, you should have at least one node other than SOURCE_FILE
+        return None;
+    }
+
+    Some(syntax_node_to_json(
+        node,
+        Some(InStringCtx {
+            offset: string_node.text_range_between_quotes()?.start().into(),
+            marker_positions,
+        }),
+    ))
+}
+
+struct InStringCtx {
+    offset: u32,
+    marker_positions: Vec<u32>,
+}
+
+#[cfg(test)]
+mod tests {
+    use expect_test::expect;
+
+    use crate::fixture;
+
+    fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: expect_test::Expect) {
+        let (analysis, file_id) = fixture::file(ra_fixture);
+        let syn = analysis.view_syntax_tree(file_id).unwrap();
+        expect.assert_eq(&syn)
+    }
+
+    #[test]
+    fn view_syntax_tree() {
+        // Basic syntax
+        check(
+            r#"fn foo() {}"#,
+            expect![[
+                r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":11,"children":[{"type":"Node","kind":"FN","start":0,"end":11,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":6,"children":[{"type":"Token","kind":"IDENT","start":3,"end":6}]},{"type":"Node","kind":"PARAM_LIST","start":6,"end":8,"children":[{"type":"Token","kind":"L_PAREN","start":6,"end":7},{"type":"Token","kind":"R_PAREN","start":7,"end":8}]},{"type":"Token","kind":"WHITESPACE","start":8,"end":9},{"type":"Node","kind":"BLOCK_EXPR","start":9,"end":11,"children":[{"type":"Node","kind":"STMT_LIST","start":9,"end":11,"children":[{"type":"Token","kind":"L_CURLY","start":9,"end":10},{"type":"Token","kind":"R_CURLY","start":10,"end":11}]}]}]}]}"#
+            ]],
+        );
+
+        check(
+            r#"
+fn test() {
+    assert!("
+    fn foo() {
+    }
+    ", "");
+}"#,
+            expect![[
+                r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":60,"children":[{"type":"Node","kind":"FN","start":0,"end":60,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":7,"children":[{"type":"Token","kind":"IDENT","start":3,"end":7}]},{"type":"Node","kind":"PARAM_LIST","start":7,"end":9,"children":[{"type":"Token","kind":"L_PAREN","start":7,"end":8},{"type":"Token","kind":"R_PAREN","start":8,"end":9}]},{"type":"Token","kind":"WHITESPACE","start":9,"end":10},{"type":"Node","kind":"BLOCK_EXPR","start":10,"end":60,"children":[{"type":"Node","kind":"STMT_LIST","start":10,"end":60,"children":[{"type":"Token","kind":"L_CURLY","start":10,"end":11},{"type":"Token","kind":"WHITESPACE","start":11,"end":16},{"type":"Node","kind":"EXPR_STMT","start":16,"end":58,"children":[{"type":"Node","kind":"MACRO_EXPR","start":16,"end":57,"children":[{"type":"Node","kind":"MACRO_CALL","start":16,"end":57,"children":[{"type":"Node","kind":"PATH","start":16,"end":22,"children":[{"type":"Node","kind":"PATH_SEGMENT","start":16,"end":22,"children":[{"type":"Node","kind":"NAME_REF","start":16,"end":22,"children":[{"type":"Token","kind":"IDENT","start":16,"end":22}]}]}]},{"type":"Token","kind":"BANG","start":22,"end":23},{"type":"Node","kind":"TOKEN_TREE","start":23,"end":57,"children":[{"type":"Token","kind":"L_PAREN","start":23,"end":24},{"type":"Node","kind":"STRING","start":24,"end":52,"children":[{"type":"Node","kind":"SOURCE_FILE","start":25,"end":51,"istart":0,"iend":26,"children":[{"type":"Token","kind":"WHITESPACE","start":25,"end":30,"istart":0,"iend":5},{"type":"Node","kind":"FN","start":30,"end":46,"istart":5,"iend":21,"children":[{"type":"Token","kind":"FN_KW","start":30,"end":32,"istart":5,"iend":7},{"type":"Token","kind":"WHITESPACE","start":32,"end":33,"istart":7,"iend":8},{"type":"Node","kind":"NAME","start":33,"end":36,"istart":8,"iend":11,"children":[{"type":"Token","kind":"IDENT","start":33,"end":36,"istart":8,"iend":11}]},{"type":"Node","kind":"PARAM_LIST","start":36,"end":38,"istart":11,"iend":13,"children":[{"type":"Token","kind":"L_PAREN","start":36,"end":37,"istart":11,"iend":12},{"type":"Token","kind":"R_PAREN","start":37,"end":38,"istart":12,"iend":13}]},{"type":"Token","kind":"WHITESPACE","start":38,"end":39,"istart":13,"iend":14},{"type":"Node","kind":"BLOCK_EXPR","start":39,"end":46,"istart":14,"iend":21,"children":[{"type":"Node","kind":"STMT_LIST","start":39,"end":46,"istart":14,"iend":21,"children":[{"type":"Token","kind":"L_CURLY","start":39,"end":40,"istart":14,"iend":15},{"type":"Token","kind":"WHITESPACE","start":40,"end":45,"istart":15,"iend":20},{"type":"Token","kind":"R_CURLY","start":45,"end":46,"istart":20,"iend":21}]}]}]},{"type":"Token","kind":"WHITESPACE","start":46,"end":51,"istart":21,"iend":26}]}]},{"type":"Token","kind":"COMMA","start":52,"end":53},{"type":"Token","kind":"WHITESPACE","start":53,"end":54},{"type":"Token","kind":"STRING","start":54,"end":56},{"type":"Token","kind":"R_PAREN","start":56,"end":57}]}]}]},{"type":"Token","kind":"SEMICOLON","start":57,"end":58}]},{"type":"Token","kind":"WHITESPACE","start":58,"end":59},{"type":"Token","kind":"R_CURLY","start":59,"end":60}]}]}]}]}"#
+            ]],
+        )
+    }
+
+    #[test]
+    fn view_syntax_tree_inside_string() {
+        check(
+            r#"fn test() {
+    assert!("
+$0fn foo() {
+}$0
+fn bar() {
+}
+    ", "");
+}"#,
+            expect![[
+                r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":65,"children":[{"type":"Node","kind":"FN","start":0,"end":65,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":7,"children":[{"type":"Token","kind":"IDENT","start":3,"end":7}]},{"type":"Node","kind":"PARAM_LIST","start":7,"end":9,"children":[{"type":"Token","kind":"L_PAREN","start":7,"end":8},{"type":"Token","kind":"R_PAREN","start":8,"end":9}]},{"type":"Token","kind":"WHITESPACE","start":9,"end":10},{"type":"Node","kind":"BLOCK_EXPR","start":10,"end":65,"children":[{"type":"Node","kind":"STMT_LIST","start":10,"end":65,"children":[{"type":"Token","kind":"L_CURLY","start":10,"end":11},{"type":"Token","kind":"WHITESPACE","start":11,"end":16},{"type":"Node","kind":"EXPR_STMT","start":16,"end":63,"children":[{"type":"Node","kind":"MACRO_EXPR","start":16,"end":62,"children":[{"type":"Node","kind":"MACRO_CALL","start":16,"end":62,"children":[{"type":"Node","kind":"PATH","start":16,"end":22,"children":[{"type":"Node","kind":"PATH_SEGMENT","start":16,"end":22,"children":[{"type":"Node","kind":"NAME_REF","start":16,"end":22,"children":[{"type":"Token","kind":"IDENT","start":16,"end":22}]}]}]},{"type":"Token","kind":"BANG","start":22,"end":23},{"type":"Node","kind":"TOKEN_TREE","start":23,"end":62,"children":[{"type":"Token","kind":"L_PAREN","start":23,"end":24},{"type":"Node","kind":"STRING","start":24,"end":57,"children":[{"type":"Node","kind":"SOURCE_FILE","start":25,"end":56,"istart":0,"iend":31,"children":[{"type":"Token","kind":"WHITESPACE","start":25,"end":26,"istart":0,"iend":1},{"type":"Node","kind":"FN","start":26,"end":38,"istart":1,"iend":13,"children":[{"type":"Token","kind":"FN_KW","start":26,"end":28,"istart":1,"iend":3},{"type":"Token","kind":"WHITESPACE","start":28,"end":29,"istart":3,"iend":4},{"type":"Node","kind":"NAME","start":29,"end":32,"istart":4,"iend":7,"children":[{"type":"Token","kind":"IDENT","start":29,"end":32,"istart":4,"iend":7}]},{"type":"Node","kind":"PARAM_LIST","start":32,"end":34,"istart":7,"iend":9,"children":[{"type":"Token","kind":"L_PAREN","start":32,"end":33,"istart":7,"iend":8},{"type":"Token","kind":"R_PAREN","start":33,"end":34,"istart":8,"iend":9}]},{"type":"Token","kind":"WHITESPACE","start":34,"end":35,"istart":9,"iend":10},{"type":"Node","kind":"BLOCK_EXPR","start":35,"end":38,"istart":10,"iend":13,"children":[{"type":"Node","kind":"STMT_LIST","start":35,"end":38,"istart":10,"iend":13,"children":[{"type":"Token","kind":"L_CURLY","start":35,"end":36,"istart":10,"iend":11},{"type":"Token","kind":"WHITESPACE","start":36,"end":37,"istart":11,"iend":12},{"type":"Token","kind":"R_CURLY","start":37,"end":38,"istart":12,"iend":13}]}]}]},{"type":"Token","kind":"WHITESPACE","start":38,"end":39,"istart":13,"iend":14},{"type":"Node","kind":"FN","start":39,"end":51,"istart":14,"iend":26,"children":[{"type":"Token","kind":"FN_KW","start":39,"end":41,"istart":14,"iend":16},{"type":"Token","kind":"WHITESPACE","start":41,"end":42,"istart":16,"iend":17},{"type":"Node","kind":"NAME","start":42,"end":45,"istart":17,"iend":20,"children":[{"type":"Token","kind":"IDENT","start":42,"end":45,"istart":17,"iend":20}]},{"type":"Node","kind":"PARAM_LIST","start":45,"end":47,"istart":20,"iend":22,"children":[{"type":"Token","kind":"L_PAREN","start":45,"end":46,"istart":20,"iend":21},{"type":"Token","kind":"R_PAREN","start":46,"end":47,"istart":21,"iend":22}]},{"type":"Token","kind":"WHITESPACE","start":47,"end":48,"istart":22,"iend":23},{"type":"Node","kind":"BLOCK_EXPR","start":48,"end":51,"istart":23,"iend":26,"children":[{"type":"Node","kind":"STMT_LIST","start":48,"end":51,"istart":23,"iend":26,"children":[{"type":"Token","kind":"L_CURLY","start":48,"end":49,"istart":23,"iend":24},{"type":"Token","kind":"WHITESPACE","start":49,"end":50,"istart":24,"iend":25},{"type":"Token","kind":"R_CURLY","start":50,"end":51,"istart":25,"iend":26}]}]}]},{"type":"Token","kind":"WHITESPACE","start":51,"end":56,"istart":26,"iend":31}]}]},{"type":"Token","kind":"COMMA","start":57,"end":58},{"type":"Token","kind":"WHITESPACE","start":58,"end":59},{"type":"Token","kind":"STRING","start":59,"end":61},{"type":"Token","kind":"R_PAREN","start":61,"end":62}]}]}]},{"type":"Token","kind":"SEMICOLON","start":62,"end":63}]},{"type":"Token","kind":"WHITESPACE","start":63,"end":64},{"type":"Token","kind":"R_CURLY","start":64,"end":65}]}]}]}]}"#
+            ]],
+        );
+
+        // With a raw string
+        check(
+            r###"fn test() {
+    assert!(r#"
+$0fn foo() {
+}$0
+fn bar() {
+}
+    "#, "");
+}"###,
+            expect![[
+                r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":68,"children":[{"type":"Node","kind":"FN","start":0,"end":68,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":7,"children":[{"type":"Token","kind":"IDENT","start":3,"end":7}]},{"type":"Node","kind":"PARAM_LIST","start":7,"end":9,"children":[{"type":"Token","kind":"L_PAREN","start":7,"end":8},{"type":"Token","kind":"R_PAREN","start":8,"end":9}]},{"type":"Token","kind":"WHITESPACE","start":9,"end":10},{"type":"Node","kind":"BLOCK_EXPR","start":10,"end":68,"children":[{"type":"Node","kind":"STMT_LIST","start":10,"end":68,"children":[{"type":"Token","kind":"L_CURLY","start":10,"end":11},{"type":"Token","kind":"WHITESPACE","start":11,"end":16},{"type":"Node","kind":"EXPR_STMT","start":16,"end":66,"children":[{"type":"Node","kind":"MACRO_EXPR","start":16,"end":65,"children":[{"type":"Node","kind":"MACRO_CALL","start":16,"end":65,"children":[{"type":"Node","kind":"PATH","start":16,"end":22,"children":[{"type":"Node","kind":"PATH_SEGMENT","start":16,"end":22,"children":[{"type":"Node","kind":"NAME_REF","start":16,"end":22,"children":[{"type":"Token","kind":"IDENT","start":16,"end":22}]}]}]},{"type":"Token","kind":"BANG","start":22,"end":23},{"type":"Node","kind":"TOKEN_TREE","start":23,"end":65,"children":[{"type":"Token","kind":"L_PAREN","start":23,"end":24},{"type":"Node","kind":"STRING","start":24,"end":60,"children":[{"type":"Node","kind":"SOURCE_FILE","start":27,"end":58,"istart":0,"iend":31,"children":[{"type":"Token","kind":"WHITESPACE","start":27,"end":28,"istart":0,"iend":1},{"type":"Node","kind":"FN","start":28,"end":40,"istart":1,"iend":13,"children":[{"type":"Token","kind":"FN_KW","start":28,"end":30,"istart":1,"iend":3},{"type":"Token","kind":"WHITESPACE","start":30,"end":31,"istart":3,"iend":4},{"type":"Node","kind":"NAME","start":31,"end":34,"istart":4,"iend":7,"children":[{"type":"Token","kind":"IDENT","start":31,"end":34,"istart":4,"iend":7}]},{"type":"Node","kind":"PARAM_LIST","start":34,"end":36,"istart":7,"iend":9,"children":[{"type":"Token","kind":"L_PAREN","start":34,"end":35,"istart":7,"iend":8},{"type":"Token","kind":"R_PAREN","start":35,"end":36,"istart":8,"iend":9}]},{"type":"Token","kind":"WHITESPACE","start":36,"end":37,"istart":9,"iend":10},{"type":"Node","kind":"BLOCK_EXPR","start":37,"end":40,"istart":10,"iend":13,"children":[{"type":"Node","kind":"STMT_LIST","start":37,"end":40,"istart":10,"iend":13,"children":[{"type":"Token","kind":"L_CURLY","start":37,"end":38,"istart":10,"iend":11},{"type":"Token","kind":"WHITESPACE","start":38,"end":39,"istart":11,"iend":12},{"type":"Token","kind":"R_CURLY","start":39,"end":40,"istart":12,"iend":13}]}]}]},{"type":"Token","kind":"WHITESPACE","start":40,"end":41,"istart":13,"iend":14},{"type":"Node","kind":"FN","start":41,"end":53,"istart":14,"iend":26,"children":[{"type":"Token","kind":"FN_KW","start":41,"end":43,"istart":14,"iend":16},{"type":"Token","kind":"WHITESPACE","start":43,"end":44,"istart":16,"iend":17},{"type":"Node","kind":"NAME","start":44,"end":47,"istart":17,"iend":20,"children":[{"type":"Token","kind":"IDENT","start":44,"end":47,"istart":17,"iend":20}]},{"type":"Node","kind":"PARAM_LIST","start":47,"end":49,"istart":20,"iend":22,"children":[{"type":"Token","kind":"L_PAREN","start":47,"end":48,"istart":20,"iend":21},{"type":"Token","kind":"R_PAREN","start":48,"end":49,"istart":21,"iend":22}]},{"type":"Token","kind":"WHITESPACE","start":49,"end":50,"istart":22,"iend":23},{"type":"Node","kind":"BLOCK_EXPR","start":50,"end":53,"istart":23,"iend":26,"children":[{"type":"Node","kind":"STMT_LIST","start":50,"end":53,"istart":23,"iend":26,"children":[{"type":"Token","kind":"L_CURLY","start":50,"end":51,"istart":23,"iend":24},{"type":"Token","kind":"WHITESPACE","start":51,"end":52,"istart":24,"iend":25},{"type":"Token","kind":"R_CURLY","start":52,"end":53,"istart":25,"iend":26}]}]}]},{"type":"Token","kind":"WHITESPACE","start":53,"end":58,"istart":26,"iend":31}]}]},{"type":"Token","kind":"COMMA","start":60,"end":61},{"type":"Token","kind":"WHITESPACE","start":61,"end":62},{"type":"Token","kind":"STRING","start":62,"end":64},{"type":"Token","kind":"R_PAREN","start":64,"end":65}]}]}]},{"type":"Token","kind":"SEMICOLON","start":65,"end":66}]},{"type":"Token","kind":"WHITESPACE","start":66,"end":67},{"type":"Token","kind":"R_CURLY","start":67,"end":68}]}]}]}]}"#
+            ]],
+        );
+
+        // With a raw string
+        check(
+            r###"fn test() {
+    assert!(r$0#"
+fn foo() {
+}
+fn bar() {
+}"$0#, "");
+}"###,
+            expect![[
+                r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":63,"children":[{"type":"Node","kind":"FN","start":0,"end":63,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":7,"children":[{"type":"Token","kind":"IDENT","start":3,"end":7}]},{"type":"Node","kind":"PARAM_LIST","start":7,"end":9,"children":[{"type":"Token","kind":"L_PAREN","start":7,"end":8},{"type":"Token","kind":"R_PAREN","start":8,"end":9}]},{"type":"Token","kind":"WHITESPACE","start":9,"end":10},{"type":"Node","kind":"BLOCK_EXPR","start":10,"end":63,"children":[{"type":"Node","kind":"STMT_LIST","start":10,"end":63,"children":[{"type":"Token","kind":"L_CURLY","start":10,"end":11},{"type":"Token","kind":"WHITESPACE","start":11,"end":16},{"type":"Node","kind":"EXPR_STMT","start":16,"end":61,"children":[{"type":"Node","kind":"MACRO_EXPR","start":16,"end":60,"children":[{"type":"Node","kind":"MACRO_CALL","start":16,"end":60,"children":[{"type":"Node","kind":"PATH","start":16,"end":22,"children":[{"type":"Node","kind":"PATH_SEGMENT","start":16,"end":22,"children":[{"type":"Node","kind":"NAME_REF","start":16,"end":22,"children":[{"type":"Token","kind":"IDENT","start":16,"end":22}]}]}]},{"type":"Token","kind":"BANG","start":22,"end":23},{"type":"Node","kind":"TOKEN_TREE","start":23,"end":60,"children":[{"type":"Token","kind":"L_PAREN","start":23,"end":24},{"type":"Node","kind":"STRING","start":24,"end":55,"children":[{"type":"Node","kind":"SOURCE_FILE","start":27,"end":53,"istart":0,"iend":26,"children":[{"type":"Token","kind":"WHITESPACE","start":27,"end":28,"istart":0,"iend":1},{"type":"Node","kind":"FN","start":28,"end":40,"istart":1,"iend":13,"children":[{"type":"Token","kind":"FN_KW","start":28,"end":30,"istart":1,"iend":3},{"type":"Token","kind":"WHITESPACE","start":30,"end":31,"istart":3,"iend":4},{"type":"Node","kind":"NAME","start":31,"end":34,"istart":4,"iend":7,"children":[{"type":"Token","kind":"IDENT","start":31,"end":34,"istart":4,"iend":7}]},{"type":"Node","kind":"PARAM_LIST","start":34,"end":36,"istart":7,"iend":9,"children":[{"type":"Token","kind":"L_PAREN","start":34,"end":35,"istart":7,"iend":8},{"type":"Token","kind":"R_PAREN","start":35,"end":36,"istart":8,"iend":9}]},{"type":"Token","kind":"WHITESPACE","start":36,"end":37,"istart":9,"iend":10},{"type":"Node","kind":"BLOCK_EXPR","start":37,"end":40,"istart":10,"iend":13,"children":[{"type":"Node","kind":"STMT_LIST","start":37,"end":40,"istart":10,"iend":13,"children":[{"type":"Token","kind":"L_CURLY","start":37,"end":38,"istart":10,"iend":11},{"type":"Token","kind":"WHITESPACE","start":38,"end":39,"istart":11,"iend":12},{"type":"Token","kind":"R_CURLY","start":39,"end":40,"istart":12,"iend":13}]}]}]},{"type":"Token","kind":"WHITESPACE","start":40,"end":41,"istart":13,"iend":14},{"type":"Node","kind":"FN","start":41,"end":53,"istart":14,"iend":26,"children":[{"type":"Token","kind":"FN_KW","start":41,"end":43,"istart":14,"iend":16},{"type":"Token","kind":"WHITESPACE","start":43,"end":44,"istart":16,"iend":17},{"type":"Node","kind":"NAME","start":44,"end":47,"istart":17,"iend":20,"children":[{"type":"Token","kind":"IDENT","start":44,"end":47,"istart":17,"iend":20}]},{"type":"Node","kind":"PARAM_LIST","start":47,"end":49,"istart":20,"iend":22,"children":[{"type":"Token","kind":"L_PAREN","start":47,"end":48,"istart":20,"iend":21},{"type":"Token","kind":"R_PAREN","start":48,"end":49,"istart":21,"iend":22}]},{"type":"Token","kind":"WHITESPACE","start":49,"end":50,"istart":22,"iend":23},{"type":"Node","kind":"BLOCK_EXPR","start":50,"end":53,"istart":23,"iend":26,"children":[{"type":"Node","kind":"STMT_LIST","start":50,"end":53,"istart":23,"iend":26,"children":[{"type":"Token","kind":"L_CURLY","start":50,"end":51,"istart":23,"iend":24},{"type":"Token","kind":"WHITESPACE","start":51,"end":52,"istart":24,"iend":25},{"type":"Token","kind":"R_CURLY","start":52,"end":53,"istart":25,"iend":26}]}]}]}]}]},{"type":"Token","kind":"COMMA","start":55,"end":56},{"type":"Token","kind":"WHITESPACE","start":56,"end":57},{"type":"Token","kind":"STRING","start":57,"end":59},{"type":"Token","kind":"R_PAREN","start":59,"end":60}]}]}]},{"type":"Token","kind":"SEMICOLON","start":60,"end":61}]},{"type":"Token","kind":"WHITESPACE","start":61,"end":62},{"type":"Token","kind":"R_CURLY","start":62,"end":63}]}]}]}]}"#
+            ]],
+        );
+    }
+}
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 66b8900109c..b3b46421b50 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
@@ -174,6 +174,7 @@ define_symbols! {
     const_param_ty,
     Context,
     Continue,
+    convert,
     copy,
     Copy,
     core_panic,
@@ -239,6 +240,8 @@ define_symbols! {
     format_unsafe_arg,
     format,
     freeze,
+    From,
+    FromStr,
     from_output,
     from_residual,
     from_usize,
@@ -429,6 +432,7 @@ define_symbols! {
     shr,
     simd,
     sized,
+    skip,
     slice_len_fn,
     Some,
     start,
@@ -456,6 +460,7 @@ define_symbols! {
     transmute_trait,
     transparent,
     Try,
+    TryFrom,
     tuple_trait,
     u128,
     u16,
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 73899408652..00446b27cf2 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -242,9 +242,6 @@ impl ProjectFolders {
                     }
                 }
 
-                if dirs.include.is_empty() {
-                    continue;
-                }
                 vfs::loader::Entry::Directories(dirs)
             };
 
@@ -267,7 +264,7 @@ impl ProjectFolders {
             };
 
             let file_set_roots = vec![VfsPath::from(ratoml_path.to_owned())];
-            let entry = vfs::loader::Entry::Files(vec![ratoml_path]);
+            let entry = vfs::loader::Entry::Files(vec![ratoml_path.to_owned()]);
 
             res.watch.push(res.load.len());
             res.load.push(entry);
diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
index 9255c5a6899..7710ea79389 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
@@ -38,7 +38,10 @@ impl<'t> Bindings<'t> {
             nesting_state.hit = true;
             b = match b {
                 Binding::Fragment(_) => break,
-                Binding::Missing(_) => break,
+                Binding::Missing(_) => {
+                    nesting_state.at_end = true;
+                    break;
+                }
                 Binding::Nested(bs) => bs.get(nesting_state.idx).ok_or_else(|| {
                     nesting_state.at_end = true;
                     binding_err!("could not find nested binding `{name}`")
@@ -445,6 +448,7 @@ fn expand_repeat(
     let mut counter = 0;
     let mut err = None;
 
+    let initial_restore_point = builder.restore_point();
     let mut restore_point = builder.restore_point();
     loop {
         let ExpandResult { value: (), err: e } =
@@ -462,6 +466,10 @@ fn expand_repeat(
 
         counter += 1;
         if counter == limit {
+            // FIXME: This is a bug here, we get here when we shouldn't, see https://github.com/rust-lang/rust-analyzer/issues/18910.
+            // If we don't restore we emit a lot of nodes which causes a stack overflow down the road. For now just ignore them,
+            // there is always an error here anyway.
+            builder.restore(initial_restore_point);
             err = Some(ExpandError::new(ctx.call_site, ExpandErrorKind::LimitExceeded));
             break;
         }
diff --git a/src/tools/rust-analyzer/crates/mbe/src/lib.rs b/src/tools/rust-analyzer/crates/mbe/src/lib.rs
index 6abf56d4b37..bebd29ef747 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/lib.rs
@@ -369,7 +369,8 @@ pub fn expect_fragment<'t>(
 ) -> ExpandResult<tt::TokenTreesView<'t, Span>> {
     use ::parser;
     let buffer = tt_iter.remaining();
-    let parser_input = to_parser_input(edition, buffer);
+    // FIXME: Pass the correct edition per token. Due to the split between mbe and hir-expand it's complicated.
+    let parser_input = to_parser_input(buffer, &mut |_ctx| edition);
     let tree_traversal = entry_point.parse(&parser_input, edition);
     let mut cursor = buffer.cursor();
     let mut error = false;
diff --git a/src/tools/rust-analyzer/crates/mbe/src/tests.rs b/src/tools/rust-analyzer/crates/mbe/src/tests.rs
index e63ad113ffd..fb68d35a4c8 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/tests.rs
@@ -26,7 +26,7 @@ fn check_(
             file_id: EditionedFileId::new(FileId::from_raw(0), def_edition),
             ast_id: ErasedFileAstId::from_raw(0),
         },
-        SyntaxContextId::ROOT,
+        SyntaxContextId::root(Edition::CURRENT),
         decl,
     )
     .unwrap();
@@ -39,16 +39,20 @@ fn check_(
         file_id: EditionedFileId::new(FileId::from_raw(1), call_edition),
         ast_id: ErasedFileAstId::from_raw(0),
     };
-    let arg_tt =
-        syntax_bridge::parse_to_token_tree(call_edition, call_anchor, SyntaxContextId::ROOT, arg)
-            .unwrap();
+    let arg_tt = syntax_bridge::parse_to_token_tree(
+        call_edition,
+        call_anchor,
+        SyntaxContextId::root(Edition::CURRENT),
+        arg,
+    )
+    .unwrap();
     let res = mac.expand(
         &arg_tt,
         |_| (),
         Span {
             range: TextRange::up_to(TextSize::of(arg)),
             anchor: call_anchor,
-            ctx: SyntaxContextId::ROOT,
+            ctx: SyntaxContextId::root(Edition::CURRENT),
         },
         def_edition,
     );
@@ -59,7 +63,12 @@ fn check_(
     if render_debug {
         format_to!(expect_res, "{:#?}\n\n", res.value.0);
     }
-    let (node, _) = syntax_bridge::token_tree_to_syntax_node(&res.value.0, parse, def_edition);
+    let (node, _) = syntax_bridge::token_tree_to_syntax_node(
+        &res.value.0,
+        parse,
+        &mut |_| def_edition,
+        def_edition,
+    );
     format_to!(
         expect_res,
         "{}",
@@ -106,25 +115,25 @@ fn token_mapping_smoke_test() {
 struct MyTraitMap2
 "#,
         expect![[r#"
-            SUBTREE $$ 1:0@0..20#0 1:0@0..20#0
-              IDENT   struct 0:0@34..40#0
-              IDENT   MyTraitMap2 1:0@8..19#0
-              SUBTREE {} 0:0@48..49#0 0:0@100..101#0
-                IDENT   map 0:0@58..61#0
-                PUNCH   : [alone] 0:0@61..62#0
-                PUNCH   : [joint] 0:0@63..64#0
-                PUNCH   : [alone] 0:0@64..65#0
-                IDENT   std 0:0@65..68#0
-                PUNCH   : [joint] 0:0@68..69#0
-                PUNCH   : [alone] 0:0@69..70#0
-                IDENT   collections 0:0@70..81#0
-                PUNCH   : [joint] 0:0@81..82#0
-                PUNCH   : [alone] 0:0@82..83#0
-                IDENT   HashSet 0:0@83..90#0
-                PUNCH   < [alone] 0:0@90..91#0
-                SUBTREE () 0:0@91..92#0 0:0@92..93#0
-                PUNCH   > [joint] 0:0@93..94#0
-                PUNCH   , [alone] 0:0@94..95#0
+            SUBTREE $$ 1:0@0..20#2 1:0@0..20#2
+              IDENT   struct 0:0@34..40#2
+              IDENT   MyTraitMap2 1:0@8..19#2
+              SUBTREE {} 0:0@48..49#2 0:0@100..101#2
+                IDENT   map 0:0@58..61#2
+                PUNCH   : [alone] 0:0@61..62#2
+                PUNCH   : [joint] 0:0@63..64#2
+                PUNCH   : [alone] 0:0@64..65#2
+                IDENT   std 0:0@65..68#2
+                PUNCH   : [joint] 0:0@68..69#2
+                PUNCH   : [alone] 0:0@69..70#2
+                IDENT   collections 0:0@70..81#2
+                PUNCH   : [joint] 0:0@81..82#2
+                PUNCH   : [alone] 0:0@82..83#2
+                IDENT   HashSet 0:0@83..90#2
+                PUNCH   < [alone] 0:0@90..91#2
+                SUBTREE () 0:0@91..92#2 0:0@92..93#2
+                PUNCH   > [joint] 0:0@93..94#2
+                PUNCH   , [alone] 0:0@94..95#2
 
             struct MyTraitMap2 {
                 map: ::std::collections::HashSet<()>,
@@ -153,28 +162,28 @@ fn main() {
 }
 "#,
         expect![[r#"
-            SUBTREE $$ 1:0@0..63#0 1:0@0..63#0
-              IDENT   fn 1:0@1..3#0
-              IDENT   main 1:0@4..8#0
-              SUBTREE () 1:0@8..9#0 1:0@9..10#0
-              SUBTREE {} 1:0@11..12#0 1:0@61..62#0
-                LITERAL Integer 1 1:0@17..18#0
-                PUNCH   ; [alone] 1:0@18..19#0
-                LITERAL Float 1.0 1:0@24..27#0
-                PUNCH   ; [alone] 1:0@27..28#0
-                SUBTREE () 1:0@33..34#0 1:0@39..40#0
-                  SUBTREE () 1:0@34..35#0 1:0@37..38#0
-                    LITERAL Integer 1 1:0@35..36#0
-                    PUNCH   , [alone] 1:0@36..37#0
-                  PUNCH   , [alone] 1:0@38..39#0
-                PUNCH   . [alone] 1:0@40..41#0
-                LITERAL Float 0.0 1:0@41..44#0
-                PUNCH   ; [alone] 1:0@44..45#0
-                IDENT   let 1:0@50..53#0
-                IDENT   x 1:0@54..55#0
-                PUNCH   = [alone] 1:0@56..57#0
-                LITERAL Integer 1 1:0@58..59#0
-                PUNCH   ; [alone] 1:0@59..60#0
+            SUBTREE $$ 1:0@0..63#2 1:0@0..63#2
+              IDENT   fn 1:0@1..3#2
+              IDENT   main 1:0@4..8#2
+              SUBTREE () 1:0@8..9#2 1:0@9..10#2
+              SUBTREE {} 1:0@11..12#2 1:0@61..62#2
+                LITERAL Integer 1 1:0@17..18#2
+                PUNCH   ; [alone] 1:0@18..19#2
+                LITERAL Float 1.0 1:0@24..27#2
+                PUNCH   ; [alone] 1:0@27..28#2
+                SUBTREE () 1:0@33..34#2 1:0@39..40#2
+                  SUBTREE () 1:0@34..35#2 1:0@37..38#2
+                    LITERAL Integer 1 1:0@35..36#2
+                    PUNCH   , [alone] 1:0@36..37#2
+                  PUNCH   , [alone] 1:0@38..39#2
+                PUNCH   . [alone] 1:0@40..41#2
+                LITERAL Float 0.0 1:0@41..44#2
+                PUNCH   ; [alone] 1:0@44..45#2
+                IDENT   let 1:0@50..53#2
+                IDENT   x 1:0@54..55#2
+                PUNCH   = [alone] 1:0@56..57#2
+                LITERAL Integer 1 1:0@58..59#2
+                PUNCH   ; [alone] 1:0@59..60#2
 
             fn main(){
                 1;
@@ -200,14 +209,14 @@ fn expr_2021() {
     const { 1 },
 "#,
         expect![[r#"
-            SUBTREE $$ 1:0@0..25#0 1:0@0..25#0
-              IDENT   _ 1:0@5..6#0
-              PUNCH   ; [joint] 0:0@36..37#0
-              SUBTREE () 0:0@34..35#0 0:0@34..35#0
-                IDENT   const 1:0@12..17#0
-                SUBTREE {} 1:0@18..19#0 1:0@22..23#0
-                  LITERAL Integer 1 1:0@20..21#0
-              PUNCH   ; [alone] 0:0@39..40#0
+            SUBTREE $$ 1:0@0..25#2 1:0@0..25#2
+              IDENT   _ 1:0@5..6#2
+              PUNCH   ; [joint] 0:0@36..37#2
+              SUBTREE () 0:0@34..35#2 0:0@34..35#2
+                IDENT   const 1:0@12..17#2
+                SUBTREE {} 1:0@18..19#2 1:0@22..23#2
+                  LITERAL Integer 1 1:0@20..21#2
+              PUNCH   ; [alone] 0:0@39..40#2
 
             _;
             (const  {
@@ -228,13 +237,13 @@ fn expr_2021() {
         expect![[r#"
             ExpandError {
                 inner: (
-                    1:0@5..6#0,
+                    1:0@5..6#2,
                     NoMatchingRule,
                 ),
             }
 
-            SUBTREE $$ 1:0@0..8#0 1:0@0..8#0
-              PUNCH   ; [alone] 0:0@39..40#0
+            SUBTREE $$ 1:0@0..8#2 1:0@0..8#2
+              PUNCH   ; [alone] 0:0@39..40#2
 
             ;"#]],
     );
@@ -252,13 +261,13 @@ fn expr_2021() {
         expect![[r#"
             ExpandError {
                 inner: (
-                    1:0@5..10#0,
+                    1:0@5..10#2,
                     NoMatchingRule,
                 ),
             }
 
-            SUBTREE $$ 1:0@0..18#0 1:0@0..18#0
-              PUNCH   ; [alone] 0:0@39..40#0
+            SUBTREE $$ 1:0@0..18#2 1:0@0..18#2
+              PUNCH   ; [alone] 0:0@39..40#2
 
             ;"#]],
     );
@@ -278,26 +287,26 @@ fn expr_2021() {
     break 'foo bar,
 "#,
         expect![[r#"
-            SUBTREE $$ 1:0@0..76#0 1:0@0..76#0
-              LITERAL Integer 4 1:0@5..6#0
-              PUNCH   ; [joint] 0:0@41..42#0
-              LITERAL Str literal 1:0@12..21#0
-              PUNCH   ; [joint] 0:0@41..42#0
-              SUBTREE () 0:0@39..40#0 0:0@39..40#0
-                IDENT   funcall 1:0@27..34#0
-                SUBTREE () 1:0@34..35#0 1:0@35..36#0
-              PUNCH   ; [joint] 0:0@41..42#0
-              SUBTREE () 0:0@39..40#0 0:0@39..40#0
-                IDENT   future 1:0@42..48#0
-                PUNCH   . [alone] 1:0@48..49#0
-                IDENT   await 1:0@49..54#0
-              PUNCH   ; [joint] 0:0@41..42#0
-              SUBTREE () 0:0@39..40#0 0:0@39..40#0
-                IDENT   break 1:0@60..65#0
-                PUNCH   ' [joint] 1:0@66..67#0
-                IDENT   foo 1:0@67..70#0
-                IDENT   bar 1:0@71..74#0
-              PUNCH   ; [alone] 0:0@44..45#0
+            SUBTREE $$ 1:0@0..76#2 1:0@0..76#2
+              LITERAL Integer 4 1:0@5..6#2
+              PUNCH   ; [joint] 0:0@41..42#2
+              LITERAL Str literal 1:0@12..21#2
+              PUNCH   ; [joint] 0:0@41..42#2
+              SUBTREE () 0:0@39..40#2 0:0@39..40#2
+                IDENT   funcall 1:0@27..34#2
+                SUBTREE () 1:0@34..35#2 1:0@35..36#2
+              PUNCH   ; [joint] 0:0@41..42#2
+              SUBTREE () 0:0@39..40#2 0:0@39..40#2
+                IDENT   future 1:0@42..48#2
+                PUNCH   . [alone] 1:0@48..49#2
+                IDENT   await 1:0@49..54#2
+              PUNCH   ; [joint] 0:0@41..42#2
+              SUBTREE () 0:0@39..40#2 0:0@39..40#2
+                IDENT   break 1:0@60..65#2
+                PUNCH   ' [joint] 1:0@66..67#2
+                IDENT   foo 1:0@67..70#2
+                IDENT   bar 1:0@71..74#2
+              PUNCH   ; [alone] 0:0@44..45#2
 
             4;
             "literal";
@@ -319,13 +328,13 @@ fn expr_2021() {
         expect![[r#"
             ExpandError {
                 inner: (
-                    1:0@5..6#0,
+                    1:0@5..6#2,
                     NoMatchingRule,
                 ),
             }
 
-            SUBTREE $$ 1:0@0..8#0 1:0@0..8#0
-              PUNCH   ; [alone] 0:0@44..45#0
+            SUBTREE $$ 1:0@0..8#2 1:0@0..8#2
+              PUNCH   ; [alone] 0:0@44..45#2
 
             ;"#]],
     );
diff --git a/src/tools/rust-analyzer/crates/parser/src/event.rs b/src/tools/rust-analyzer/crates/parser/src/event.rs
index e38571dd3ec..b197b086f37 100644
--- a/src/tools/rust-analyzer/crates/parser/src/event.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/event.rs
@@ -12,7 +12,7 @@ use crate::{
 /// `Parser` produces a flat list of `Event`s.
 /// They are converted to a tree-structure in
 /// a separate pass, via `TreeBuilder`.
-#[derive(Debug)]
+#[derive(Debug, PartialEq)]
 pub(crate) enum Event {
     /// This event signifies the start of the node.
     /// It should be either abandoned (in which case the
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs
index 3b3f11be130..389c01933c9 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs
@@ -134,10 +134,12 @@ pub(super) fn let_stmt(p: &mut Parser<'_>, with_semi: Semicolon) {
         // test_err let_else_right_curly_brace
         // fn func() { let Some(_) = {Some(1)} else { panic!("h") };}
         if let Some(expr) = expr_after_eq {
-            if BlockLike::is_blocklike(expr.kind()) {
-                p.error(
-                    "right curly brace `}` before `else` in a `let...else` statement not allowed",
-                )
+            if let Some(token) = expr.last_token(p) {
+                if token == T!['}'] {
+                    p.error(
+                        "right curly brace `}` before `else` in a `let...else` statement not allowed"
+                    )
+                }
             }
         }
 
@@ -339,13 +341,20 @@ fn lhs(p: &mut Parser<'_>, r: Restrictions) -> Option<(CompletedMarker, BlockLik
         //     // raw reference operator
         //     let _ = &raw mut foo;
         //     let _ = &raw const foo;
+        //     let _ = &raw foo;
         // }
         T![&] => {
             m = p.start();
             p.bump(T![&]);
-            if p.at_contextual_kw(T![raw]) && [T![mut], T![const]].contains(&p.nth(1)) {
-                p.bump_remap(T![raw]);
-                p.bump_any();
+            if p.at_contextual_kw(T![raw]) {
+                if [T![mut], T![const]].contains(&p.nth(1)) {
+                    p.bump_remap(T![raw]);
+                    p.bump_any();
+                } else if p.nth_at(1, SyntaxKind::IDENT) {
+                    // we treat raw as keyword in this case
+                    // &raw foo;
+                    p.bump_remap(T![raw]);
+                }
             } else {
                 p.eat(T![mut]);
             }
diff --git a/src/tools/rust-analyzer/crates/parser/src/parser.rs b/src/tools/rust-analyzer/crates/parser/src/parser.rs
index 75a75f601cf..2f6ba525747 100644
--- a/src/tools/rust-analyzer/crates/parser/src/parser.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/parser.rs
@@ -318,7 +318,8 @@ impl Marker {
             _ => unreachable!(),
         }
         p.push_event(Event::Finish);
-        CompletedMarker::new(self.pos, kind)
+        let end_pos = p.events.len() as u32;
+        CompletedMarker::new(self.pos, end_pos, kind)
     }
 
     /// Abandons the syntax tree node. All its children
@@ -336,13 +337,14 @@ impl Marker {
 }
 
 pub(crate) struct CompletedMarker {
-    pos: u32,
+    start_pos: u32,
+    end_pos: u32,
     kind: SyntaxKind,
 }
 
 impl CompletedMarker {
-    fn new(pos: u32, kind: SyntaxKind) -> Self {
-        CompletedMarker { pos, kind }
+    fn new(start_pos: u32, end_pos: u32, kind: SyntaxKind) -> Self {
+        CompletedMarker { start_pos, end_pos, kind }
     }
 
     /// This method allows to create a new node which starts
@@ -360,10 +362,10 @@ impl CompletedMarker {
     /// distance to `NEWSTART` into forward_parent(=2 in this case);
     pub(crate) fn precede(self, p: &mut Parser<'_>) -> Marker {
         let new_pos = p.start();
-        let idx = self.pos as usize;
+        let idx = self.start_pos as usize;
         match &mut p.events[idx] {
             Event::Start { forward_parent, .. } => {
-                *forward_parent = Some(new_pos.pos - self.pos);
+                *forward_parent = Some(new_pos.pos - self.start_pos);
             }
             _ => unreachable!(),
         }
@@ -376,7 +378,7 @@ impl CompletedMarker {
         let idx = m.pos as usize;
         match &mut p.events[idx] {
             Event::Start { forward_parent, .. } => {
-                *forward_parent = Some(self.pos - m.pos);
+                *forward_parent = Some(self.start_pos - m.pos);
             }
             _ => unreachable!(),
         }
@@ -386,4 +388,13 @@ impl CompletedMarker {
     pub(crate) fn kind(&self) -> SyntaxKind {
         self.kind
     }
+
+    pub(crate) fn last_token(&self, p: &Parser<'_>) -> Option<SyntaxKind> {
+        let end_pos = self.end_pos as usize;
+        debug_assert_eq!(p.events[end_pos - 1], Event::Finish);
+        p.events[..end_pos].iter().rev().find_map(|event| match event {
+            Event::Token { kind, .. } => Some(*kind),
+            _ => None,
+        })
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0056_let_else_right_curly_brace_struct.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0056_let_else_right_curly_brace_struct.rast
new file mode 100644
index 00000000000..578dc2b0f96
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0056_let_else_right_curly_brace_struct.rast
@@ -0,0 +1,79 @@
+SOURCE_FILE
+  STRUCT
+    STRUCT_KW "struct"
+    WHITESPACE " "
+    NAME
+      IDENT "X"
+    WHITESPACE " "
+    RECORD_FIELD_LIST
+      L_CURLY "{"
+      RECORD_FIELD
+        NAME
+          IDENT "a"
+        COLON ":"
+        WHITESPACE " "
+        PATH_TYPE
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "i32"
+      R_CURLY "}"
+  WHITESPACE "\n"
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "f"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE "\n    "
+        LET_STMT
+          LET_KW "let"
+          WHITESPACE " "
+          IDENT_PAT
+            NAME
+              IDENT "foo"
+          WHITESPACE " "
+          EQ "="
+          WHITESPACE " "
+          RECORD_EXPR
+            PATH
+              PATH_SEGMENT
+                NAME_REF
+                  IDENT "X"
+            WHITESPACE " "
+            RECORD_EXPR_FIELD_LIST
+              L_CURLY "{"
+              WHITESPACE "\n        "
+              RECORD_EXPR_FIELD
+                NAME_REF
+                  IDENT "a"
+                COLON ":"
+                WHITESPACE " "
+                LITERAL
+                  INT_NUMBER "1"
+              WHITESPACE "\n    "
+              R_CURLY "}"
+          WHITESPACE " "
+          LET_ELSE
+            ELSE_KW "else"
+            WHITESPACE " "
+            BLOCK_EXPR
+              STMT_LIST
+                L_CURLY "{"
+                WHITESPACE "\n        "
+                EXPR_STMT
+                  RETURN_EXPR
+                    RETURN_KW "return"
+                  SEMICOLON ";"
+                WHITESPACE "\n    "
+                R_CURLY "}"
+          SEMICOLON ";"
+        WHITESPACE "\n"
+        R_CURLY "}"
+error 63: right curly brace `}` before `else` in a `let...else` statement not allowed
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0056_let_else_right_curly_brace_struct.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0056_let_else_right_curly_brace_struct.rs
new file mode 100644
index 00000000000..c0c0edc9830
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0056_let_else_right_curly_brace_struct.rs
@@ -0,0 +1,8 @@
+struct X {a: i32}
+fn f() {
+    let foo = X {
+        a: 1
+    } else {
+        return;
+    };
+}
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_arithmetic.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_arithmetic.rast
new file mode 100644
index 00000000000..8e994f22d41
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_arithmetic.rast
@@ -0,0 +1,42 @@
+SOURCE_FILE
+  ERROR
+    LET_KW "let"
+    WHITESPACE " "
+    IDENT_PAT
+      NAME
+        IDENT "foo"
+    WHITESPACE " "
+    EQ "="
+    WHITESPACE " "
+    BIN_EXPR
+      LITERAL
+        INT_NUMBER "1"
+      WHITESPACE " "
+      PLUS "+"
+      WHITESPACE " "
+      BLOCK_EXPR
+        STMT_LIST
+          L_CURLY "{"
+          WHITESPACE "\n    "
+          LITERAL
+            INT_NUMBER "1"
+          WHITESPACE "\n"
+          R_CURLY "}"
+    WHITESPACE " "
+    LET_ELSE
+      ELSE_KW "else"
+      WHITESPACE " "
+      BLOCK_EXPR
+        STMT_LIST
+          L_CURLY "{"
+          WHITESPACE "\n    "
+          EXPR_STMT
+            RETURN_EXPR
+              RETURN_KW "return"
+            SEMICOLON ";"
+          WHITESPACE "\n"
+          R_CURLY "}"
+    SEMICOLON ";"
+  WHITESPACE "\n"
+error 0: expected an item
+error 23: right curly brace `}` before `else` in a `let...else` statement not allowed
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_arithmetic.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_arithmetic.rs
new file mode 100644
index 00000000000..c29ddcce1ff
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_arithmetic.rs
@@ -0,0 +1,5 @@
+let foo = 1 + {
+    1
+} else {
+    return;
+};
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_format_args.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_format_args.rast
new file mode 100644
index 00000000000..055b583acec
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_format_args.rast
@@ -0,0 +1,90 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "r"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE "\n    "
+        LET_STMT
+          LET_KW "let"
+          WHITESPACE " "
+          IDENT_PAT
+            NAME
+              IDENT "ok"
+          WHITESPACE " "
+          EQ "="
+          WHITESPACE " "
+          MACRO_EXPR
+            MACRO_CALL
+              PATH
+                PATH_SEGMENT
+                  NAME_REF
+                    IDENT "format_args"
+              BANG "!"
+              TOKEN_TREE
+                L_PAREN "("
+                STRING "\"\""
+                R_PAREN ")"
+          WHITESPACE " "
+          LET_ELSE
+            ELSE_KW "else"
+            WHITESPACE " "
+            BLOCK_EXPR
+              STMT_LIST
+                L_CURLY "{"
+                WHITESPACE " "
+                EXPR_STMT
+                  RETURN_EXPR
+                    RETURN_KW "return"
+                  SEMICOLON ";"
+                WHITESPACE " "
+                R_CURLY "}"
+          SEMICOLON ";"
+        WHITESPACE "\n\n    "
+        LET_STMT
+          LET_KW "let"
+          WHITESPACE " "
+          IDENT_PAT
+            NAME
+              IDENT "bad"
+          WHITESPACE " "
+          EQ "="
+          WHITESPACE " "
+          MACRO_EXPR
+            MACRO_CALL
+              PATH
+                PATH_SEGMENT
+                  NAME_REF
+                    IDENT "format_args"
+              BANG "!"
+              WHITESPACE " "
+              TOKEN_TREE
+                L_CURLY "{"
+                STRING "\"\""
+                R_CURLY "}"
+          WHITESPACE " "
+          LET_ELSE
+            ELSE_KW "else"
+            WHITESPACE " "
+            BLOCK_EXPR
+              STMT_LIST
+                L_CURLY "{"
+                WHITESPACE " "
+                EXPR_STMT
+                  RETURN_EXPR
+                    RETURN_KW "return"
+                  SEMICOLON ";"
+                WHITESPACE " "
+                R_CURLY "}"
+          SEMICOLON ";"
+        WHITESPACE "\n"
+        R_CURLY "}"
+  WHITESPACE "\n"
+error 89: right curly brace `}` before `else` in a `let...else` statement not allowed
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_format_args.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_format_args.rs
new file mode 100644
index 00000000000..5916fa07dc2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_format_args.rs
@@ -0,0 +1,5 @@
+fn r() {
+    let ok = format_args!("") else { return; };
+
+    let bad = format_args! {""} else { return; };
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0058_let_else_right_curly_brace_range.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0058_let_else_right_curly_brace_range.rast
new file mode 100644
index 00000000000..8c7fd8c295d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0058_let_else_right_curly_brace_range.rast
@@ -0,0 +1,40 @@
+SOURCE_FILE
+  ERROR
+    LET_KW "let"
+    WHITESPACE " "
+    IDENT_PAT
+      NAME
+        IDENT "foo"
+    WHITESPACE " "
+    EQ "="
+    WHITESPACE " "
+    RANGE_EXPR
+      LITERAL
+        INT_NUMBER "1"
+      DOT2 ".."
+      BLOCK_EXPR
+        STMT_LIST
+          L_CURLY "{"
+          WHITESPACE "\n    "
+          LITERAL
+            INT_NUMBER "1"
+          WHITESPACE "\n"
+          R_CURLY "}"
+    WHITESPACE " "
+    LET_ELSE
+      ELSE_KW "else"
+      WHITESPACE " "
+      BLOCK_EXPR
+        STMT_LIST
+          L_CURLY "{"
+          WHITESPACE "\n    "
+          EXPR_STMT
+            RETURN_EXPR
+              RETURN_KW "return"
+            SEMICOLON ";"
+          WHITESPACE "\n"
+          R_CURLY "}"
+    SEMICOLON ";"
+  WHITESPACE "\n"
+error 0: expected an item
+error 22: right curly brace `}` before `else` in a `let...else` statement not allowed
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0058_let_else_right_curly_brace_range.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0058_let_else_right_curly_brace_range.rs
new file mode 100644
index 00000000000..5417131d28e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0058_let_else_right_curly_brace_range.rs
@@ -0,0 +1,5 @@
+let foo = 1..{
+    1
+} else {
+    return;
+};
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0059_let_else_right_curly_brace_closure.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0059_let_else_right_curly_brace_closure.rast
new file mode 100644
index 00000000000..57925a0d192
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0059_let_else_right_curly_brace_closure.rast
@@ -0,0 +1,55 @@
+SOURCE_FILE
+  ERROR
+    LET_KW "let"
+    WHITESPACE " "
+    IDENT_PAT
+      NAME
+        IDENT "foo"
+    WHITESPACE " "
+    EQ "="
+    WHITESPACE " "
+    CLOSURE_EXPR
+      PARAM_LIST
+        PIPE "|"
+        PARAM
+          IDENT_PAT
+            NAME
+              IDENT "x"
+          COLON ":"
+          WHITESPACE " "
+          PATH_TYPE
+            PATH
+              PATH_SEGMENT
+                NAME_REF
+                  IDENT "i32"
+        PIPE "|"
+      WHITESPACE " "
+      BLOCK_EXPR
+        STMT_LIST
+          L_CURLY "{"
+          WHITESPACE "\n    "
+          PATH_EXPR
+            PATH
+              PATH_SEGMENT
+                NAME_REF
+                  IDENT "x"
+          WHITESPACE "\n"
+          R_CURLY "}"
+    WHITESPACE " "
+    LET_ELSE
+      ELSE_KW "else"
+      WHITESPACE " "
+      BLOCK_EXPR
+        STMT_LIST
+          L_CURLY "{"
+          WHITESPACE "\n    "
+          EXPR_STMT
+            RETURN_EXPR
+              RETURN_KW "return"
+            SEMICOLON ";"
+          WHITESPACE "\n"
+          R_CURLY "}"
+    SEMICOLON ";"
+  WHITESPACE "\n"
+error 0: expected an item
+error 28: right curly brace `}` before `else` in a `let...else` statement not allowed
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0059_let_else_right_curly_brace_closure.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0059_let_else_right_curly_brace_closure.rs
new file mode 100644
index 00000000000..89c7579b071
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0059_let_else_right_curly_brace_closure.rs
@@ -0,0 +1,5 @@
+let foo = |x: i32| {
+    x
+} else {
+    return;
+};
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0060_let_else_right_curly_brace_unary.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0060_let_else_right_curly_brace_unary.rast
new file mode 100644
index 00000000000..4fb70bd50e3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0060_let_else_right_curly_brace_unary.rast
@@ -0,0 +1,38 @@
+SOURCE_FILE
+  ERROR
+    LET_KW "let"
+    WHITESPACE " "
+    IDENT_PAT
+      NAME
+        IDENT "foo"
+    WHITESPACE " "
+    EQ "="
+    WHITESPACE " "
+    PREFIX_EXPR
+      MINUS "-"
+      BLOCK_EXPR
+        STMT_LIST
+          L_CURLY "{"
+          WHITESPACE "\n    "
+          LITERAL
+            INT_NUMBER "1"
+          WHITESPACE "\n"
+          R_CURLY "}"
+    WHITESPACE " "
+    LET_ELSE
+      ELSE_KW "else"
+      WHITESPACE " "
+      BLOCK_EXPR
+        STMT_LIST
+          L_CURLY "{"
+          WHITESPACE "\n    "
+          EXPR_STMT
+            RETURN_EXPR
+              RETURN_KW "return"
+            SEMICOLON ";"
+          WHITESPACE "\n"
+          R_CURLY "}"
+    SEMICOLON ";"
+  WHITESPACE "\n"
+error 0: expected an item
+error 20: right curly brace `}` before `else` in a `let...else` statement not allowed
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0060_let_else_right_curly_brace_unary.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0060_let_else_right_curly_brace_unary.rs
new file mode 100644
index 00000000000..1ba7f7d761b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0060_let_else_right_curly_brace_unary.rs
@@ -0,0 +1,5 @@
+let foo = -{
+    1
+} else {
+    return;
+};
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0061_let_else_right_curly_brace_do_yeet.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0061_let_else_right_curly_brace_do_yeet.rast
new file mode 100644
index 00000000000..e8eeeee695e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0061_let_else_right_curly_brace_do_yeet.rast
@@ -0,0 +1,90 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "o"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    RET_TYPE
+      THIN_ARROW "->"
+      WHITESPACE " "
+      PATH_TYPE
+        PATH
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "Result"
+            GENERIC_ARG_LIST
+              L_ANGLE "<"
+              TYPE_ARG
+                TUPLE_TYPE
+                  L_PAREN "("
+                  R_PAREN ")"
+              COMMA ","
+              WHITESPACE " "
+              TYPE_ARG
+                TUPLE_TYPE
+                  L_PAREN "("
+                  R_PAREN ")"
+              R_ANGLE ">"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE "\n    "
+        LET_STMT
+          LET_KW "let"
+          WHITESPACE " "
+          IDENT_PAT
+            NAME
+              IDENT "foo"
+          WHITESPACE " "
+          EQ "="
+          WHITESPACE " "
+          YEET_EXPR
+            DO_KW "do"
+            WHITESPACE " "
+            YEET_KW "yeet"
+            WHITESPACE " "
+            BLOCK_EXPR
+              STMT_LIST
+                L_CURLY "{"
+                WHITESPACE "\n        "
+                TUPLE_EXPR
+                  L_PAREN "("
+                  R_PAREN ")"
+                WHITESPACE "\n    "
+                R_CURLY "}"
+          WHITESPACE " "
+          LET_ELSE
+            ELSE_KW "else"
+            WHITESPACE " "
+            BLOCK_EXPR
+              STMT_LIST
+                L_CURLY "{"
+                WHITESPACE "\n        "
+                EXPR_STMT
+                  RETURN_EXPR
+                    RETURN_KW "return"
+                    WHITESPACE " "
+                    CALL_EXPR
+                      PATH_EXPR
+                        PATH
+                          PATH_SEGMENT
+                            NAME_REF
+                              IDENT "Ok"
+                      ARG_LIST
+                        L_PAREN "("
+                        TUPLE_EXPR
+                          L_PAREN "("
+                          R_PAREN ")"
+                        R_PAREN ")"
+                  SEMICOLON ";"
+                WHITESPACE "\n    "
+                R_CURLY "}"
+          SEMICOLON ";"
+        WHITESPACE "\n"
+        R_CURLY "}"
+error 67: right curly brace `}` before `else` in a `let...else` statement not allowed
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0061_let_else_right_curly_brace_do_yeet.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0061_let_else_right_curly_brace_do_yeet.rs
new file mode 100644
index 00000000000..188fb07d91b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0061_let_else_right_curly_brace_do_yeet.rs
@@ -0,0 +1,7 @@
+fn o() -> Result<(), ()> {
+    let foo = do yeet {
+        ()
+    } else {
+        return Ok(());
+    };
+}
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0062_let_else_right_curly_brace_become.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0062_let_else_right_curly_brace_become.rast
new file mode 100644
index 00000000000..cc5e1278c3d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0062_let_else_right_curly_brace_become.rast
@@ -0,0 +1,40 @@
+SOURCE_FILE
+  ERROR
+    LET_KW "let"
+    WHITESPACE " "
+    IDENT_PAT
+      NAME
+        IDENT "foo"
+    WHITESPACE " "
+    EQ "="
+    WHITESPACE " "
+    BECOME_EXPR
+      BECOME_KW "become"
+      WHITESPACE " "
+      BLOCK_EXPR
+        STMT_LIST
+          L_CURLY "{"
+          WHITESPACE "\n    "
+          TUPLE_EXPR
+            L_PAREN "("
+            R_PAREN ")"
+          WHITESPACE "\n"
+          R_CURLY "}"
+    WHITESPACE " "
+    LET_ELSE
+      ELSE_KW "else"
+      WHITESPACE " "
+      BLOCK_EXPR
+        STMT_LIST
+          L_CURLY "{"
+          WHITESPACE "\n    "
+          EXPR_STMT
+            RETURN_EXPR
+              RETURN_KW "return"
+            SEMICOLON ";"
+          WHITESPACE "\n"
+          R_CURLY "}"
+    SEMICOLON ";"
+  WHITESPACE "\n"
+error 0: expected an item
+error 27: right curly brace `}` before `else` in a `let...else` statement not allowed
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0062_let_else_right_curly_brace_become.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0062_let_else_right_curly_brace_become.rs
new file mode 100644
index 00000000000..622548b8f33
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0062_let_else_right_curly_brace_become.rs
@@ -0,0 +1,5 @@
+let foo = become {
+    ()
+} else {
+    return;
+};
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0063_let_else_right_curly_brace_reference.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0063_let_else_right_curly_brace_reference.rast
new file mode 100644
index 00000000000..ea2f4f28e2d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0063_let_else_right_curly_brace_reference.rast
@@ -0,0 +1,38 @@
+SOURCE_FILE
+  ERROR
+    LET_KW "let"
+    WHITESPACE " "
+    IDENT_PAT
+      NAME
+        IDENT "foo"
+    WHITESPACE " "
+    EQ "="
+    WHITESPACE " "
+    REF_EXPR
+      AMP "&"
+      BLOCK_EXPR
+        STMT_LIST
+          L_CURLY "{"
+          WHITESPACE "\n    "
+          LITERAL
+            INT_NUMBER "1"
+          WHITESPACE "\n"
+          R_CURLY "}"
+    WHITESPACE " "
+    LET_ELSE
+      ELSE_KW "else"
+      WHITESPACE " "
+      BLOCK_EXPR
+        STMT_LIST
+          L_CURLY "{"
+          WHITESPACE "\n    "
+          EXPR_STMT
+            RETURN_EXPR
+              RETURN_KW "return"
+            SEMICOLON ";"
+          WHITESPACE "\n"
+          R_CURLY "}"
+    SEMICOLON ";"
+  WHITESPACE "\n"
+error 0: expected an item
+error 20: right curly brace `}` before `else` in a `let...else` statement not allowed
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0063_let_else_right_curly_brace_reference.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0063_let_else_right_curly_brace_reference.rs
new file mode 100644
index 00000000000..9a00dca3689
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0063_let_else_right_curly_brace_reference.rs
@@ -0,0 +1,5 @@
+let foo = &{
+    1
+} else {
+    return;
+};
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0064_let_else_right_curly_brace_assignment.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0064_let_else_right_curly_brace_assignment.rast
new file mode 100644
index 00000000000..47396140c5c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0064_let_else_right_curly_brace_assignment.rast
@@ -0,0 +1,45 @@
+SOURCE_FILE
+  ERROR
+    LET_KW "let"
+    WHITESPACE " "
+    IDENT_PAT
+      NAME
+        IDENT "foo"
+    WHITESPACE " "
+    EQ "="
+    WHITESPACE " "
+    BIN_EXPR
+      PATH_EXPR
+        PATH
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "bar"
+      WHITESPACE " "
+      EQ "="
+      WHITESPACE " "
+      BLOCK_EXPR
+        STMT_LIST
+          L_CURLY "{"
+          WHITESPACE "\n    "
+          LITERAL
+            INT_NUMBER "1"
+          WHITESPACE "\n"
+          R_CURLY "}"
+    WHITESPACE " "
+    LET_ELSE
+      ELSE_KW "else"
+      WHITESPACE " "
+      BLOCK_EXPR
+        STMT_LIST
+          L_CURLY "{"
+          WHITESPACE "\n    "
+          EXPR_STMT
+            RETURN_EXPR
+              RETURN_KW "return"
+            SEMICOLON ";"
+          WHITESPACE "\n"
+          R_CURLY "}"
+    SEMICOLON ";"
+  WHITESPACE "\n"
+error 0: expected an item
+error 25: right curly brace `}` before `else` in a `let...else` statement not allowed
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0064_let_else_right_curly_brace_assignment.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0064_let_else_right_curly_brace_assignment.rs
new file mode 100644
index 00000000000..08e677416f1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0064_let_else_right_curly_brace_assignment.rs
@@ -0,0 +1,5 @@
+let foo = bar = {
+    1
+} else {
+    return;
+};
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rast
index 108b0802c33..8dc916e5cc5 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rast
@@ -134,6 +134,25 @@ SOURCE_FILE
                   NAME_REF
                     IDENT "foo"
           SEMICOLON ";"
+        WHITESPACE "\n    "
+        LET_STMT
+          LET_KW "let"
+          WHITESPACE " "
+          WILDCARD_PAT
+            UNDERSCORE "_"
+          WHITESPACE " "
+          EQ "="
+          WHITESPACE " "
+          REF_EXPR
+            AMP "&"
+            RAW_KW "raw"
+            WHITESPACE " "
+            PATH_EXPR
+              PATH
+                PATH_SEGMENT
+                  NAME_REF
+                    IDENT "foo"
+          SEMICOLON ";"
         WHITESPACE "\n"
         R_CURLY "}"
   WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rs
index c5262f4469b..31a2485b439 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rs
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rs
@@ -7,4 +7,5 @@ fn foo() {
     // raw reference operator
     let _ = &raw mut foo;
     let _ = &raw const foo;
+    let _ = &raw foo;
 }
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs
index 6ea8db9a905..4b831e4aceb 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs
@@ -159,7 +159,7 @@ type ProtocolWrite<W: Write> = for<'o, 'msg> fn(out: &'o mut W, msg: &'msg str)
 #[cfg(test)]
 mod tests {
     use intern::{sym, Symbol};
-    use span::{ErasedFileAstId, Span, SpanAnchor, SyntaxContextId, TextRange, TextSize};
+    use span::{Edition, ErasedFileAstId, Span, SpanAnchor, SyntaxContextId, TextRange, TextSize};
     use tt::{
         Delimiter, DelimiterKind, Ident, Leaf, Literal, Punct, Spacing, TopSubtree,
         TopSubtreeBuilder,
@@ -180,12 +180,12 @@ mod tests {
             open: Span {
                 range: TextRange::empty(TextSize::new(0)),
                 anchor,
-                ctx: SyntaxContextId::ROOT,
+                ctx: SyntaxContextId::root(Edition::CURRENT),
             },
             close: Span {
                 range: TextRange::empty(TextSize::new(19)),
                 anchor,
-                ctx: SyntaxContextId::ROOT,
+                ctx: SyntaxContextId::root(Edition::CURRENT),
             },
             kind: DelimiterKind::Invisible,
         });
@@ -196,7 +196,7 @@ mod tests {
                 span: Span {
                     range: TextRange::at(TextSize::new(0), TextSize::of("struct")),
                     anchor,
-                    ctx: SyntaxContextId::ROOT,
+                    ctx: SyntaxContextId::root(Edition::CURRENT),
                 },
                 is_raw: tt::IdentIsRaw::No,
             }
@@ -208,7 +208,7 @@ mod tests {
                 span: Span {
                     range: TextRange::at(TextSize::new(5), TextSize::of("r#Foo")),
                     anchor,
-                    ctx: SyntaxContextId::ROOT,
+                    ctx: SyntaxContextId::root(Edition::CURRENT),
                 },
                 is_raw: tt::IdentIsRaw::Yes,
             }
@@ -219,7 +219,7 @@ mod tests {
             span: Span {
                 range: TextRange::at(TextSize::new(10), TextSize::of("\"Foo\"")),
                 anchor,
-                ctx: SyntaxContextId::ROOT,
+                ctx: SyntaxContextId::root(Edition::CURRENT),
             },
             kind: tt::LitKind::Str,
             suffix: None,
@@ -229,7 +229,7 @@ mod tests {
             span: Span {
                 range: TextRange::at(TextSize::new(13), TextSize::of('@')),
                 anchor,
-                ctx: SyntaxContextId::ROOT,
+                ctx: SyntaxContextId::root(Edition::CURRENT),
             },
             spacing: Spacing::Joint,
         }));
@@ -238,7 +238,7 @@ mod tests {
             Span {
                 range: TextRange::at(TextSize::new(14), TextSize::of('{')),
                 anchor,
-                ctx: SyntaxContextId::ROOT,
+                ctx: SyntaxContextId::root(Edition::CURRENT),
             },
         );
         builder.push(Leaf::Literal(Literal {
@@ -246,7 +246,7 @@ mod tests {
             span: Span {
                 range: TextRange::at(TextSize::new(15), TextSize::of("0u32")),
                 anchor,
-                ctx: SyntaxContextId::ROOT,
+                ctx: SyntaxContextId::root(Edition::CURRENT),
             },
             kind: tt::LitKind::Integer,
             suffix: Some(sym::u32.clone()),
@@ -254,7 +254,7 @@ mod tests {
         builder.close(Span {
             range: TextRange::at(TextSize::new(19), TextSize::of('}')),
             anchor,
-            ctx: SyntaxContextId::ROOT,
+            ctx: SyntaxContextId::root(Edition::CURRENT),
         });
 
         builder.build()
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml
index 00695c54737..191535ac55e 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml
@@ -14,6 +14,7 @@ doctest = false
 
 [dependencies]
 object.workspace = true
+libc.workspace = true
 libloading.workspace = true
 memmap2.workspace = true
 
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs
index fe15d42b4e4..cbf7a277bfa 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs
@@ -28,11 +28,16 @@ fn load_library(file: &Utf8Path) -> Result<Library, libloading::Error> {
 
 #[cfg(unix)]
 fn load_library(file: &Utf8Path) -> Result<Library, libloading::Error> {
+    // not defined by POSIX, different values on mips vs other targets
+    #[cfg(target_env = "gnu")]
+    use libc::RTLD_DEEPBIND;
     use libloading::os::unix::Library as UnixLibrary;
-    use std::os::raw::c_int;
+    // defined by POSIX
+    use libloading::os::unix::RTLD_NOW;
 
-    const RTLD_NOW: c_int = 0x00002;
-    const RTLD_DEEPBIND: c_int = 0x00008;
+    // MUSL and bionic don't have it..
+    #[cfg(not(target_env = "gnu"))]
+    const RTLD_DEEPBIND: std::os::raw::c_int = 0x0;
 
     unsafe { UnixLibrary::open(Some(file), RTLD_NOW | RTLD_DEEPBIND).map(|lib| lib.into()) }
 }
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
index beaebf33300..c7614849e01 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
@@ -440,7 +440,7 @@ mod tests {
                 file_id: EditionedFileId::current_edition(FileId::from_raw(0)),
                 ast_id: span::ErasedFileAstId::from_raw(0),
             },
-            ctx: SyntaxContextId::ROOT,
+            ctx: SyntaxContextId::root(span::Edition::CURRENT),
         };
         let s = TokenStream {
             token_trees: vec![
@@ -482,7 +482,7 @@ mod tests {
                 file_id: EditionedFileId::current_edition(FileId::from_raw(0)),
                 ast_id: span::ErasedFileAstId::from_raw(0),
             },
-            ctx: SyntaxContextId::ROOT,
+            ctx: SyntaxContextId::root(span::Edition::CURRENT),
         };
         let subtree_paren_a = vec![
             tt::TokenTree::Subtree(tt::Subtree {
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
index dc6e71163b2..15de88ea656 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
@@ -12,7 +12,7 @@ fn test_derive_empty() {
         "DeriveEmpty",
         r#"struct S;"#,
         expect!["SUBTREE $$ 1 1"],
-        expect!["SUBTREE $$ 42:2@0..100#0 42:2@0..100#0"],
+        expect!["SUBTREE $$ 42:2@0..100#2 42:2@0..100#2"],
     );
 }
 
@@ -29,12 +29,12 @@ fn test_derive_error() {
                 LITERAL Str #[derive(DeriveError)] struct S ; 1
               PUNCH   ; [alone] 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#0 42:2@0..100#0
-              IDENT   compile_error 42:2@0..100#0
-              PUNCH   ! [alone] 42:2@0..100#0
-              SUBTREE () 42:2@0..100#0 42:2@0..100#0
-                LITERAL Str #[derive(DeriveError)] struct S ; 42:2@0..100#0
-              PUNCH   ; [alone] 42:2@0..100#0"#]],
+            SUBTREE $$ 42:2@0..100#2 42:2@0..100#2
+              IDENT   compile_error 42:2@0..100#2
+              PUNCH   ! [alone] 42:2@0..100#2
+              SUBTREE () 42:2@0..100#2 42:2@0..100#2
+                LITERAL Str #[derive(DeriveError)] struct S ; 42:2@0..100#2
+              PUNCH   ; [alone] 42:2@0..100#2"#]],
     );
 }
 
@@ -53,14 +53,14 @@ fn test_fn_like_macro_noop() {
               PUNCH   , [alone] 1
               SUBTREE [] 1 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#0 42:2@0..100#0
-              IDENT   ident 42:2@0..5#0
-              PUNCH   , [alone] 42:2@5..6#0
-              LITERAL Integer 0 42:2@7..8#0
-              PUNCH   , [alone] 42:2@8..9#0
-              LITERAL Integer 1 42:2@10..11#0
-              PUNCH   , [alone] 42:2@11..12#0
-              SUBTREE [] 42:2@13..14#0 42:2@14..15#0"#]],
+            SUBTREE $$ 42:2@0..100#2 42:2@0..100#2
+              IDENT   ident 42:2@0..5#2
+              PUNCH   , [alone] 42:2@5..6#2
+              LITERAL Integer 0 42:2@7..8#2
+              PUNCH   , [alone] 42:2@8..9#2
+              LITERAL Integer 1 42:2@10..11#2
+              PUNCH   , [alone] 42:2@11..12#2
+              SUBTREE [] 42:2@13..14#2 42:2@14..15#2"#]],
     );
 }
 
@@ -75,10 +75,10 @@ fn test_fn_like_macro_clone_ident_subtree() {
               PUNCH   , [alone] 1
               SUBTREE [] 1 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#0 42:2@0..100#0
-              IDENT   ident 42:2@0..5#0
-              PUNCH   , [alone] 42:2@5..6#0
-              SUBTREE [] 42:2@7..8#0 42:2@7..8#0"#]],
+            SUBTREE $$ 42:2@0..100#2 42:2@0..100#2
+              IDENT   ident 42:2@0..5#2
+              PUNCH   , [alone] 42:2@5..6#2
+              SUBTREE [] 42:2@7..8#2 42:2@7..8#2"#]],
     );
 }
 
@@ -91,8 +91,8 @@ fn test_fn_like_macro_clone_raw_ident() {
             SUBTREE $$ 1 1
               IDENT   r#async 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#0 42:2@0..100#0
-              IDENT   r#async 42:2@0..7#0"#]],
+            SUBTREE $$ 42:2@0..100#2 42:2@0..100#2
+              IDENT   r#async 42:2@0..7#2"#]],
     );
 }
 
@@ -105,8 +105,8 @@ fn test_fn_like_fn_like_span_join() {
             SUBTREE $$ 1 1
               IDENT   r#joined 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#0 42:2@0..100#0
-              IDENT   r#joined 42:2@0..11#0"#]],
+            SUBTREE $$ 42:2@0..100#2 42:2@0..100#2
+              IDENT   r#joined 42:2@0..11#2"#]],
     );
 }
 
@@ -121,10 +121,10 @@ fn test_fn_like_fn_like_span_ops() {
               IDENT   resolved_at_def_site 1
               IDENT   start_span 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#0 42:2@0..100#0
-              IDENT   set_def_site 41:1@0..150#0
-              IDENT   resolved_at_def_site 42:2@13..33#0
-              IDENT   start_span 42:2@34..34#0"#]],
+            SUBTREE $$ 42:2@0..100#2 42:2@0..100#2
+              IDENT   set_def_site 41:1@0..150#2
+              IDENT   resolved_at_def_site 42:2@13..33#2
+              IDENT   start_span 42:2@34..34#2"#]],
     );
 }
 
@@ -143,14 +143,14 @@ fn test_fn_like_mk_literals() {
               LITERAL Integer 123i64 1
               LITERAL Integer 123 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#0 42:2@0..100#0
-              LITERAL ByteStr byte_string 42:2@0..100#0
-              LITERAL Char c 42:2@0..100#0
-              LITERAL Str string 42:2@0..100#0
-              LITERAL Float 3.14f64 42:2@0..100#0
-              LITERAL Float 3.14 42:2@0..100#0
-              LITERAL Integer 123i64 42:2@0..100#0
-              LITERAL Integer 123 42:2@0..100#0"#]],
+            SUBTREE $$ 42:2@0..100#2 42:2@0..100#2
+              LITERAL ByteStr byte_string 42:2@0..100#2
+              LITERAL Char c 42:2@0..100#2
+              LITERAL Str string 42:2@0..100#2
+              LITERAL Float 3.14f64 42:2@0..100#2
+              LITERAL Float 3.14 42:2@0..100#2
+              LITERAL Integer 123i64 42:2@0..100#2
+              LITERAL Integer 123 42:2@0..100#2"#]],
     );
 }
 
@@ -164,9 +164,9 @@ fn test_fn_like_mk_idents() {
               IDENT   standard 1
               IDENT   r#raw 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#0 42:2@0..100#0
-              IDENT   standard 42:2@0..100#0
-              IDENT   r#raw 42:2@0..100#0"#]],
+            SUBTREE $$ 42:2@0..100#2 42:2@0..100#2
+              IDENT   standard 42:2@0..100#2
+              IDENT   r#raw 42:2@0..100#2"#]],
     );
 }
 
@@ -198,27 +198,27 @@ fn test_fn_like_macro_clone_literals() {
               PUNCH   , [alone] 1
               LITERAL CStr null 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#0 42:2@0..100#0
-              LITERAL Integer 1u16 42:2@0..4#0
-              PUNCH   , [alone] 42:2@4..5#0
-              LITERAL Integer 2_u32 42:2@6..11#0
-              PUNCH   , [alone] 42:2@11..12#0
-              PUNCH   - [alone] 42:2@13..14#0
-              LITERAL Integer 4i64 42:2@14..18#0
-              PUNCH   , [alone] 42:2@18..19#0
-              LITERAL Float 3.14f32 42:2@20..27#0
-              PUNCH   , [alone] 42:2@27..28#0
-              LITERAL Str hello bridge 42:2@29..43#0
-              PUNCH   , [alone] 42:2@43..44#0
-              LITERAL Str suffixedsuffix 42:2@45..61#0
-              PUNCH   , [alone] 42:2@61..62#0
-              LITERAL StrRaw(2) raw 42:2@63..73#0
-              PUNCH   , [alone] 42:2@73..74#0
-              LITERAL Char a 42:2@75..78#0
-              PUNCH   , [alone] 42:2@78..79#0
-              LITERAL Byte b 42:2@80..84#0
-              PUNCH   , [alone] 42:2@84..85#0
-              LITERAL CStr null 42:2@86..93#0"#]],
+            SUBTREE $$ 42:2@0..100#2 42:2@0..100#2
+              LITERAL Integer 1u16 42:2@0..4#2
+              PUNCH   , [alone] 42:2@4..5#2
+              LITERAL Integer 2_u32 42:2@6..11#2
+              PUNCH   , [alone] 42:2@11..12#2
+              PUNCH   - [alone] 42:2@13..14#2
+              LITERAL Integer 4i64 42:2@14..18#2
+              PUNCH   , [alone] 42:2@18..19#2
+              LITERAL Float 3.14f32 42:2@20..27#2
+              PUNCH   , [alone] 42:2@27..28#2
+              LITERAL Str hello bridge 42:2@29..43#2
+              PUNCH   , [alone] 42:2@43..44#2
+              LITERAL Str suffixedsuffix 42:2@45..61#2
+              PUNCH   , [alone] 42:2@61..62#2
+              LITERAL StrRaw(2) raw 42:2@63..73#2
+              PUNCH   , [alone] 42:2@73..74#2
+              LITERAL Char a 42:2@75..78#2
+              PUNCH   , [alone] 42:2@78..79#2
+              LITERAL Byte b 42:2@80..84#2
+              PUNCH   , [alone] 42:2@84..85#2
+              LITERAL CStr null 42:2@86..93#2"#]],
     );
 }
 
@@ -239,12 +239,12 @@ fn test_attr_macro() {
                 LITERAL Str #[attr_error(some arguments)] mod m {} 1
               PUNCH   ; [alone] 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#0 42:2@0..100#0
-              IDENT   compile_error 42:2@0..100#0
-              PUNCH   ! [alone] 42:2@0..100#0
-              SUBTREE () 42:2@0..100#0 42:2@0..100#0
-                LITERAL Str #[attr_error(some arguments)] mod m {} 42:2@0..100#0
-              PUNCH   ; [alone] 42:2@0..100#0"#]],
+            SUBTREE $$ 42:2@0..100#2 42:2@0..100#2
+              IDENT   compile_error 42:2@0..100#2
+              PUNCH   ! [alone] 42:2@0..100#2
+              SUBTREE () 42:2@0..100#2 42:2@0..100#2
+                LITERAL Str #[attr_error(some arguments)] mod m {} 42:2@0..100#2
+              PUNCH   ; [alone] 42:2@0..100#2"#]],
     );
 }
 
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs
index 37d51050f32..4ce4544243a 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs
@@ -28,13 +28,18 @@ fn parse_string_spanned(
     ))
 }
 
-pub fn assert_expand(macro_name: &str, ra_fixture: &str, expect: Expect, expect_s: Expect) {
+pub fn assert_expand(
+    macro_name: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    expect: Expect,
+    expect_s: Expect,
+) {
     assert_expand_impl(macro_name, ra_fixture, None, expect, expect_s);
 }
 
 pub fn assert_expand_attr(
     macro_name: &str,
-    ra_fixture: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
     attr_args: &str,
     expect: Expect,
     expect_s: Expect,
@@ -76,7 +81,7 @@ fn assert_expand_impl(
             file_id: EditionedFileId::current_edition(FileId::from_raw(41)),
             ast_id: ErasedFileAstId::from_raw(1),
         },
-        ctx: SyntaxContextId::ROOT,
+        ctx: SyntaxContextId::root(span::Edition::CURRENT),
     };
     let call_site = Span {
         range: TextRange::new(0.into(), 100.into()),
@@ -84,7 +89,7 @@ fn assert_expand_impl(
             file_id: EditionedFileId::current_edition(FileId::from_raw(42)),
             ast_id: ErasedFileAstId::from_raw(2),
         },
-        ctx: SyntaxContextId::ROOT,
+        ctx: SyntaxContextId::root(span::Edition::CURRENT),
     };
     let mixed_site = call_site;
 
diff --git a/src/tools/rust-analyzer/crates/profile/Cargo.toml b/src/tools/rust-analyzer/crates/profile/Cargo.toml
index 2e3413f339b..3179c810f69 100644
--- a/src/tools/rust-analyzer/crates/profile/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/profile/Cargo.toml
@@ -21,7 +21,10 @@ jemalloc-ctl = { version = "0.5.0", package = "tikv-jemalloc-ctl", optional = tr
 perf-event = "=0.4.7"
 
 [target.'cfg(windows)'.dependencies]
-windows-sys = { version = "0.52", features = ["Win32_System_Threading", "Win32_System_ProcessStatus"] }
+windows-sys = { version = "0.59", features = [
+    "Win32_System_Threading",
+    "Win32_System_ProcessStatus",
+] }
 
 [features]
 cpu_profiler = []
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 4d906c2aeb3..e4a61134620 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
@@ -92,6 +92,8 @@ pub struct CargoConfig {
     pub sysroot_src: Option<AbsPathBuf>,
     /// rustc private crate source
     pub rustc_source: Option<RustLibSource>,
+    /// Extra includes to add to the VFS.
+    pub extra_includes: Vec<AbsPathBuf>,
     pub cfg_overrides: CfgOverrides,
     /// Invoke `cargo check` through the RUSTC_WRAPPER.
     pub wrap_rustc_in_build_scripts: bool,
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 681bce3a5a6..f1113831125 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
@@ -49,6 +49,7 @@ fn load_workspace_from_metadata(file: &str) -> ProjectWorkspace {
         rustc_cfg: Vec::new(),
         toolchain: None,
         target_layout: Err("target_data_layout not loaded".into()),
+        extra_includes: Vec::new(),
     }
 }
 
@@ -63,6 +64,7 @@ fn load_rust_project(file: &str) -> (CrateGraph, ProcMacroPaths) {
         toolchain: None,
         target_layout: Err(Arc::from("test has no data layout")),
         cfg_overrides: Default::default(),
+        extra_includes: Vec::new(),
     };
     to_crate_graph(project_workspace, &mut Default::default())
 }
@@ -284,6 +286,7 @@ fn smoke_test_real_sysroot_cargo() {
         cfg_overrides: Default::default(),
         toolchain: None,
         target_layout: Err("target_data_layout not loaded".into()),
+        extra_includes: Vec::new(),
     };
     project_workspace.to_crate_graph(
         &mut {
diff --git a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs
index afcc8120794..4bf9b59e7d0 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs
@@ -66,7 +66,7 @@ fn rustc_print_cfg(
         QueryConfig::Cargo(sysroot, cargo_toml) => {
             let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent());
             cmd.envs(extra_env);
-            cmd.args(["rustc"]).args(RUSTC_ARGS);
+            cmd.args(["rustc", "-Z", "unstable-options"]).args(RUSTC_ARGS);
             if let Some(target) = target {
                 cmd.args(["--target", target]);
             }
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 a345c6bcce4..f98d983ac06 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -11,9 +11,8 @@ use base_db::{
 };
 use cfg::{CfgAtom, CfgDiff, CfgOptions};
 use intern::{sym, Symbol};
-use itertools::Itertools;
 use paths::{AbsPath, AbsPathBuf};
-use rustc_hash::FxHashMap;
+use rustc_hash::{FxHashMap, FxHashSet};
 use semver::Version;
 use span::{Edition, FileId};
 use tracing::instrument;
@@ -63,6 +62,8 @@ pub struct ProjectWorkspace {
     pub target_layout: TargetLayoutLoadResult,
     /// A set of cfg overrides for this workspace.
     pub cfg_overrides: CfgOverrides,
+    /// Additional includes to add for the VFS.
+    pub extra_includes: Vec<AbsPathBuf>,
 }
 
 #[derive(Clone)]
@@ -104,7 +105,15 @@ pub enum ProjectWorkspaceKind {
 impl fmt::Debug for ProjectWorkspace {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         // Make sure this isn't too verbose.
-        let Self { kind, sysroot, rustc_cfg, toolchain, target_layout, cfg_overrides } = self;
+        let Self {
+            kind,
+            sysroot,
+            rustc_cfg,
+            toolchain,
+            target_layout,
+            cfg_overrides,
+            extra_includes,
+        } = self;
         match kind {
             ProjectWorkspaceKind::Cargo { cargo, error: _, build_scripts, rustc, set_test } => f
                 .debug_struct("Cargo")
@@ -117,6 +126,7 @@ impl fmt::Debug for ProjectWorkspace {
                 )
                 .field("n_rustc_cfg", &rustc_cfg.len())
                 .field("n_cfg_overrides", &cfg_overrides.len())
+                .field("n_extra_includes", &extra_includes.len())
                 .field("toolchain", &toolchain)
                 .field("data_layout", &target_layout)
                 .field("set_test", set_test)
@@ -130,7 +140,8 @@ impl fmt::Debug for ProjectWorkspace {
                     .field("n_rustc_cfg", &rustc_cfg.len())
                     .field("toolchain", &toolchain)
                     .field("data_layout", &target_layout)
-                    .field("n_cfg_overrides", &cfg_overrides.len());
+                    .field("n_cfg_overrides", &cfg_overrides.len())
+                    .field("n_extra_includes", &extra_includes.len());
 
                 debug_struct.finish()
             }
@@ -144,6 +155,7 @@ impl fmt::Debug for ProjectWorkspace {
                 .field("toolchain", &toolchain)
                 .field("data_layout", &target_layout)
                 .field("n_cfg_overrides", &cfg_overrides.len())
+                .field("n_extra_includes", &extra_includes.len())
                 .field("set_test", set_test)
                 .finish(),
         }
@@ -320,6 +332,7 @@ impl ProjectWorkspace {
             cfg_overrides,
             toolchain,
             target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())),
+            extra_includes: config.extra_includes.clone(),
         })
     }
 
@@ -340,6 +353,7 @@ impl ProjectWorkspace {
             toolchain,
             target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())),
             cfg_overrides: config.cfg_overrides.clone(),
+            extra_includes: config.extra_includes.clone(),
         }
     }
 
@@ -399,6 +413,7 @@ impl ProjectWorkspace {
             toolchain,
             target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())),
             cfg_overrides: config.cfg_overrides.clone(),
+            extra_includes: config.extra_includes.clone(),
         })
     }
 
@@ -565,13 +580,20 @@ impl ProjectWorkspace {
 
                     PackageRoot {
                         is_local: krate.is_workspace_member,
-                        include: krate.include.iter().cloned().chain(build_file).collect(),
+                        include: krate
+                            .include
+                            .iter()
+                            .cloned()
+                            .chain(build_file)
+                            .chain(self.extra_includes.iter().cloned())
+                            .collect(),
                         exclude: krate.exclude.clone(),
                     }
                 })
+                .collect::<FxHashSet<_>>()
+                .into_iter()
                 .chain(mk_sysroot())
-                .unique()
-                .collect(),
+                .collect::<Vec<_>>(),
             ProjectWorkspaceKind::Cargo { cargo, rustc, build_scripts, error: _, set_test: _ } => {
                 cargo
                     .packages()
@@ -603,6 +625,8 @@ impl ProjectWorkspace {
 
                         let mut exclude = vec![pkg_root.join(".git")];
                         if is_local {
+                            include.extend(self.extra_includes.iter().cloned());
+
                             exclude.push(pkg_root.join("target"));
                         } else {
                             exclude.push(pkg_root.join("tests"));
@@ -619,11 +643,6 @@ impl ProjectWorkspace {
                             exclude: Vec::new(),
                         })
                     }))
-                    .chain(cargo.is_virtual_workspace().then(|| PackageRoot {
-                        is_local: true,
-                        include: vec![cargo.workspace_root().to_path_buf()],
-                        exclude: Vec::new(),
-                    }))
                     .collect()
             }
             ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script, .. } => {
@@ -661,6 +680,8 @@ impl ProjectWorkspace {
 
                         let mut exclude = vec![pkg_root.join(".git")];
                         if is_local {
+                            include.extend(self.extra_includes.iter().cloned());
+
                             exclude.push(pkg_root.join("target"));
                         } else {
                             exclude.push(pkg_root.join("tests"));
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
index d06130ce8c5..c24cbb4a311 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
@@ -76,7 +76,10 @@ vfs.workspace = true
 paths.workspace = true
 
 [target.'cfg(windows)'.dependencies]
-windows-sys = { version = "0.52", features = ["Win32_System_Diagnostics_Debug", "Win32_System_Threading"] }
+windows-sys = { version = "0.59", features = [
+  "Win32_System_Diagnostics_Debug",
+  "Win32_System_Threading",
+] }
 
 [target.'cfg(not(target_env = "msvc"))'.dependencies]
 jemallocator = { version = "0.5.0", package = "tikv-jemallocator", optional = true }
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 afe3455b780..bcaec520195 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
@@ -1051,6 +1051,7 @@ impl flags::AnalysisStats {
                 &InlayHintsConfig {
                     render_colons: false,
                     type_hints: true,
+                    sized_bound: false,
                     discriminant_hints: ide::DiscriminantHints::Always,
                     parameter_hints: true,
                     generic_parameter_hints: ide::GenericParameterHints {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
index 6b0ce4db7c9..199f61e70f0 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
@@ -93,6 +93,7 @@ impl Tester {
             toolchain: None,
             target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())),
             cfg_overrides: Default::default(),
+            extra_includes: vec![],
         };
         let load_cargo_config = LoadCargoConfig {
             load_out_dirs_from_check: false,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
index 6ca7d9ac057..dc0f722aae6 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
@@ -518,7 +518,7 @@ mod test {
     use test_fixture::ChangeFixture;
     use vfs::VfsPath;
 
-    fn position(ra_fixture: &str) -> (AnalysisHost, FilePosition) {
+    fn position(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (AnalysisHost, FilePosition) {
         let mut host = AnalysisHost::default();
         let change_fixture = ChangeFixture::parse(ra_fixture);
         host.raw_database_mut().apply_change(change_fixture.change);
@@ -530,7 +530,7 @@ mod test {
 
     /// If expected == "", then assert that there are no symbols (this is basically local symbol)
     #[track_caller]
-    fn check_symbol(ra_fixture: &str, expected: &str) {
+    fn check_symbol(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected: &str) {
         let (host, position) = position(ra_fixture);
 
         let analysis = host.analysis();
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 30f0031905f..3dc4379258f 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -185,6 +185,8 @@ config_data! {
         inlayHints_genericParameterHints_type_enable: bool = false,
         /// Whether to show implicit drop hints.
         inlayHints_implicitDrops_enable: bool                      = false,
+        /// Whether to show inlay hints for the implied type parameter `Sized` bound.
+        inlayHints_implicitSizedBoundHints_enable: bool            = false,
         /// Whether to show inlay type hints for elided lifetimes in function signatures.
         inlayHints_lifetimeElisionHints_enable: LifetimeElisionDef = LifetimeElisionDef::Never,
         /// Whether to prefer using parameter names as the name for elided lifetime hints if possible.
@@ -324,8 +326,16 @@ config_data! {
         /// Show documentation.
         signatureInfo_documentation_enable: bool                       = true,
 
-        /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`.
-        typing_excludeChars: Option<String> = Some("|<".to_owned()),
+        /// Specify the characters allowed to invoke special on typing triggers.
+        /// - typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing expression
+        /// - typing `=` between two expressions adds `;` when in statement position
+        /// - typing `=` to turn an assignment into an equality comparison removes `;` when in expression position
+        /// - typing `.` in a chain method call auto-indents
+        /// - typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the expression
+        /// - typing `{` in a use item adds a closing `}` in the right place
+        /// - typing `>` to complete a return type `->` will insert a whitespace after it
+        /// - typing `<` in a path or type position inserts a closing `>` after the path or type.
+        typing_triggerChars: Option<String> = Some("=.".to_owned()),
 
 
         /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`].
@@ -571,11 +581,8 @@ config_data! {
         /// avoid checking unnecessary things.
         cargo_buildScripts_useRustcWrapper: bool = true,
         /// List of cfg options to enable with the given values.
-        cargo_cfgs: FxHashMap<String, Option<String>> = {
-            let mut m = FxHashMap::default();
-            m.insert("debug_assertions".to_owned(), None);
-            m.insert("miri".to_owned(), None);
-            m
+        cargo_cfgs: Vec<String> = {
+            vec!["debug_assertions".into(), "miri".into()]
         },
         /// Extra arguments that are passed to every cargo invocation.
         cargo_extraArgs: Vec<String> = vec![],
@@ -728,6 +735,10 @@ config_data! {
         /// available on a nightly build.
         rustfmt_rangeFormatting_enable: bool = false,
 
+        /// Additional paths to include in the VFS. Generally for code that is
+        /// generated or otherwise managed by a build system outside of Cargo,
+        /// though Cargo might be the eventual consumer.
+        vfs_extraIncludes: Vec<String> = vec![],
 
         /// Workspace symbol search kind.
         workspace_symbol_search_kind: WorkspaceSymbolSearchKindDef = WorkspaceSymbolSearchKindDef::OnlyTypes,
@@ -1620,6 +1631,7 @@ impl Config {
         InlayHintsConfig {
             render_colons: self.inlayHints_renderColons().to_owned(),
             type_hints: self.inlayHints_typeHints_enable().to_owned(),
+            sized_bound: self.inlayHints_implicitSizedBoundHints_enable().to_owned(),
             parameter_hints: self.inlayHints_parameterHints_enable().to_owned(),
             generic_parameter_hints: GenericParameterHints {
                 type_hints: self.inlayHints_genericParameterHints_type_enable().to_owned(),
@@ -1926,6 +1938,13 @@ impl Config {
         });
         let sysroot_src =
             self.cargo_sysrootSrc(source_root).as_ref().map(|sysroot| self.root_path.join(sysroot));
+        let extra_includes = self
+            .vfs_extraIncludes(source_root)
+            .iter()
+            .map(String::as_str)
+            .map(AbsPathBuf::try_from)
+            .filter_map(Result::ok)
+            .collect();
 
         CargoConfig {
             all_targets: *self.cargo_allTargets(source_root),
@@ -1940,10 +1959,18 @@ impl Config {
             sysroot,
             sysroot_src,
             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),
@@ -2232,8 +2259,8 @@ impl Config {
         }
     }
 
-    pub fn typing_exclude_chars(&self) -> Option<String> {
-        self.typing_excludeChars().clone()
+    pub fn typing_trigger_chars(&self) -> &str {
+        self.typing_triggerChars().as_deref().unwrap_or_default()
     }
 
     // VSCode is our reference implementation, so we allow ourselves to work around issues by
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 7ac70efe2d6..190015d7faa 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
@@ -136,15 +136,13 @@ pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> anyhow::Res
     Ok(out)
 }
 
-pub(crate) fn handle_syntax_tree(
+pub(crate) fn handle_view_syntax_tree(
     snap: GlobalStateSnapshot,
-    params: lsp_ext::SyntaxTreeParams,
+    params: lsp_ext::ViewSyntaxTreeParams,
 ) -> anyhow::Result<String> {
-    let _p = tracing::info_span!("handle_syntax_tree").entered();
+    let _p = tracing::info_span!("handle_view_syntax_tree").entered();
     let id = from_proto::file_id(&snap, &params.text_document.uri)?;
-    let line_index = snap.file_line_index(id)?;
-    let text_range = params.range.and_then(|r| from_proto::text_range(&line_index, r).ok());
-    let res = snap.analysis.syntax_tree(id, text_range)?;
+    let res = snap.analysis.view_syntax_tree(id)?;
     Ok(res)
 }
 
@@ -436,29 +434,24 @@ pub(crate) fn handle_on_type_formatting(
     params: lsp_types::DocumentOnTypeFormattingParams,
 ) -> anyhow::Result<Option<Vec<lsp_ext::SnippetTextEdit>>> {
     let _p = tracing::info_span!("handle_on_type_formatting").entered();
+    let char_typed = params.ch.chars().next().unwrap_or('\0');
+    if !snap.config.typing_trigger_chars().contains(char_typed) {
+        return Ok(None);
+    }
+
     let mut position = from_proto::file_position(&snap, params.text_document_position)?;
     let line_index = snap.file_line_index(position.file_id)?;
 
     // in `ide`, the `on_type` invariant is that
     // `text.char_at(position) == typed_char`.
     position.offset -= TextSize::of('.');
-    let char_typed = params.ch.chars().next().unwrap_or('\0');
 
     let text = snap.analysis.file_text(position.file_id)?;
     if stdx::never!(!text[usize::from(position.offset)..].starts_with(char_typed)) {
         return Ok(None);
     }
 
-    // We have an assist that inserts ` ` after typing `->` in `fn foo() ->{`,
-    // but it requires precise cursor positioning to work, and one can't
-    // position the cursor with on_type formatting. So, let's just toggle this
-    // feature off here, hoping that we'll enable it one day, 😿.
-    if char_typed == '>' {
-        return Ok(None);
-    }
-    let chars_to_exclude = snap.config.typing_exclude_chars();
-
-    let edit = snap.analysis.on_char_typed(position, char_typed, chars_to_exclude)?;
+    let edit = snap.analysis.on_char_typed(position, char_typed)?;
     let edit = match edit {
         Some(it) => it,
         None => return Ok(None),
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 e7f5a7f5e78..61ec576dd4f 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
@@ -47,7 +47,8 @@ use self::lsp::ext as lsp_ext;
 #[cfg(test)]
 mod integrated_benchmarks;
 
-use ide::{CompletionItem, CompletionRelevance};
+use hir::Mutability;
+use ide::{CompletionItem, CompletionItemRefMode, CompletionRelevance};
 use serde::de::DeserializeOwned;
 use tenthash::TentHasher;
 
@@ -132,8 +133,13 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8;
         hasher.update(detail);
     }
     hash_completion_relevance(&mut hasher, &item.relevance);
-    if let Some((mutability, text_size)) = &item.ref_match {
-        hasher.update(mutability.as_keyword_for_ref());
+    if let Some((ref_mode, text_size)) = &item.ref_match {
+        let prefix = match ref_mode {
+            CompletionItemRefMode::Reference(Mutability::Shared) => "&",
+            CompletionItemRefMode::Reference(Mutability::Mut) => "&mut ",
+            CompletionItemRefMode::Dereference => "*",
+        };
+        hasher.update(prefix);
         hasher.update(u32::from(*text_size).to_le_bytes());
     }
     for (import_path, import_name) in &item.import_to_add {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
index f50cbba7acf..134de92feab 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
@@ -108,19 +108,18 @@ impl Request for RebuildProcMacros {
     const METHOD: &'static str = "rust-analyzer/rebuildProcMacros";
 }
 
-pub enum SyntaxTree {}
+pub enum ViewSyntaxTree {}
 
-impl Request for SyntaxTree {
-    type Params = SyntaxTreeParams;
+impl Request for ViewSyntaxTree {
+    type Params = ViewSyntaxTreeParams;
     type Result = String;
-    const METHOD: &'static str = "rust-analyzer/syntaxTree";
+    const METHOD: &'static str = "rust-analyzer/viewSyntaxTree";
 }
 
 #[derive(Deserialize, Serialize, Debug)]
 #[serde(rename_all = "camelCase")]
-pub struct SyntaxTreeParams {
+pub struct ViewSyntaxTreeParams {
     pub text_document: TextDocumentIdentifier,
-    pub range: Option<Range>,
 }
 
 pub enum ViewHir {}
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 fe4d02dcb4f..a5516e7f9d4 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
@@ -547,7 +547,18 @@ pub(crate) fn inlay_hint(
     file_id: FileId,
     mut inlay_hint: InlayHint,
 ) -> Cancellable<lsp_types::InlayHint> {
-    let resolve_range_and_hash = inlay_hint.needs_resolve().map(|range| {
+    let hint_needs_resolve = |hint: &InlayHint| -> Option<TextRange> {
+        hint.resolve_parent.filter(|_| {
+            hint.text_edit.is_some()
+                || hint
+                    .label
+                    .parts
+                    .iter()
+                    .any(|part| part.linked_location.is_some() || part.tooltip.is_some())
+        })
+    };
+
+    let resolve_range_and_hash = hint_needs_resolve(&inlay_hint).map(|range| {
         (
             range,
             std::hash::BuildHasher::hash_one(
@@ -568,7 +579,11 @@ pub(crate) fn inlay_hint(
         something_to_resolve |= inlay_hint.text_edit.is_some();
         None
     } else {
-        inlay_hint.text_edit.take().map(|it| text_edit_vec(line_index, it))
+        inlay_hint
+            .text_edit
+            .take()
+            .and_then(|it| it.computed())
+            .map(|it| text_edit_vec(line_index, it))
     };
     let (label, tooltip) = inlay_hint_label(
         snap,
@@ -626,7 +641,7 @@ fn inlay_hint_label(
                 *something_to_resolve |= tooltip.is_some();
                 None
             } else {
-                match tooltip {
+                match tooltip.and_then(|it| it.computed()) {
                     Some(ide::InlayTooltip::String(s)) => {
                         Some(lsp_types::InlayHintTooltip::String(s))
                     }
@@ -650,7 +665,7 @@ fn inlay_hint_label(
                         *something_to_resolve |= part.tooltip.is_some();
                         None
                     } else {
-                        match part.tooltip {
+                        match part.tooltip.and_then(|it| it.computed()) {
                             Some(ide::InlayTooltip::String(s)) => {
                                 Some(lsp_types::InlayHintLabelPartTooltip::String(s))
                             }
@@ -1993,7 +2008,7 @@ fn bar(_: usize) {}
 
     #[track_caller]
     fn check_rendered_snippets_in_source(
-        ra_fixture: &str,
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
         edit: TextEdit,
         snippets: SnippetEdit,
         expect: Expect,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
index 97657b92658..d6dc8b521fd 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
@@ -1145,7 +1145,7 @@ impl GlobalState {
             .on::<RETRY, lsp_ext::WorkspaceSymbol>(handlers::handle_workspace_symbol)
             .on::<NO_RETRY, lsp_ext::Ssr>(handlers::handle_ssr)
             .on::<NO_RETRY, lsp_ext::ViewRecursiveMemoryLayout>(handlers::handle_view_recursive_memory_layout)
-            .on::<NO_RETRY, lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)
+            .on::<NO_RETRY, lsp_ext::ViewSyntaxTree>(handlers::handle_view_syntax_tree)
             .on::<NO_RETRY, lsp_ext::ViewHir>(handlers::handle_view_hir)
             .on::<NO_RETRY, lsp_ext::ViewMir>(handlers::handle_view_mir)
             .on::<NO_RETRY, lsp_ext::InterpretFunction>(handlers::handle_interpret_function)
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs
index 503b3ee43a1..3edfb812cf5 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs
@@ -18,7 +18,11 @@ pub(crate) enum TestState {
     Started,
     Ok,
     Ignored,
-    Failed { stdout: String },
+    Failed {
+        // the stdout field is not always present depending on cargo test flags
+        #[serde(skip_serializing_if = "String::is_empty", default)]
+        stdout: String,
+    },
 }
 
 #[derive(Debug, Deserialize)]
diff --git a/src/tools/rust-analyzer/crates/span/src/hygiene.rs b/src/tools/rust-analyzer/crates/span/src/hygiene.rs
index 87a948df550..6becc8e41ed 100644
--- a/src/tools/rust-analyzer/crates/span/src/hygiene.rs
+++ b/src/tools/rust-analyzer/crates/span/src/hygiene.rs
@@ -26,7 +26,7 @@ use crate::InternId;
 #[cfg(feature = "ra-salsa")]
 use ra_salsa::{InternId, InternValue};
 
-use crate::MacroCallId;
+use crate::{Edition, MacroCallId};
 
 /// Interned [`SyntaxContextData`].
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -59,11 +59,20 @@ impl fmt::Display for SyntaxContextId {
 }
 
 impl SyntaxContextId {
+    #[inline]
+    pub fn remove_root_edition(&mut self) {
+        if self.is_root() {
+            *self = Self::root(Edition::Edition2015);
+        }
+    }
+
     /// The root context, which is the parent of all other contexts. All [`FileId`]s have this context.
-    pub const ROOT: Self = SyntaxContextId(unsafe { InternId::new_unchecked(0) });
+    pub const fn root(edition: Edition) -> Self {
+        SyntaxContextId(unsafe { InternId::new_unchecked(edition as u32) })
+    }
 
     pub fn is_root(self) -> bool {
-        self == Self::ROOT
+        self.into_u32() <= Edition::LATEST as u32
     }
 
     /// Deconstruct a `SyntaxContextId` into a raw `u32`.
@@ -89,6 +98,7 @@ pub struct SyntaxContextData {
     // per crate. Though that is likely not a problem as `MacroCallId`s are already crate calling dependent.
     pub outer_expn: Option<MacroCallId>,
     pub outer_transparency: Transparency,
+    pub edition: Edition,
     pub parent: SyntaxContextId,
     /// This context, but with all transparent and semi-transparent expansions filtered away.
     pub opaque: SyntaxContextId,
@@ -98,10 +108,10 @@ pub struct SyntaxContextData {
 
 #[cfg(feature = "ra-salsa")]
 impl InternValue for SyntaxContextData {
-    type Key = (SyntaxContextId, Option<MacroCallId>, Transparency);
+    type Key = (SyntaxContextId, Option<MacroCallId>, Transparency, Edition);
 
     fn into_key(&self) -> Self::Key {
-        (self.parent, self.outer_expn, self.outer_transparency)
+        (self.parent, self.outer_expn, self.outer_transparency, self.edition)
     }
 }
 
@@ -118,13 +128,14 @@ impl std::fmt::Debug for SyntaxContextData {
 }
 
 impl SyntaxContextData {
-    pub fn root() -> Self {
+    pub fn root(edition: Edition) -> Self {
         SyntaxContextData {
             outer_expn: None,
             outer_transparency: Transparency::Opaque,
-            parent: SyntaxContextId::ROOT,
-            opaque: SyntaxContextId::ROOT,
-            opaque_and_semitransparent: SyntaxContextId::ROOT,
+            parent: SyntaxContextId::root(edition),
+            opaque: SyntaxContextId::root(edition),
+            opaque_and_semitransparent: SyntaxContextId::root(edition),
+            edition,
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/span/src/map.rs b/src/tools/rust-analyzer/crates/span/src/map.rs
index 66bbce18594..dc35de67fd8 100644
--- a/src/tools/rust-analyzer/crates/span/src/map.rs
+++ b/src/tools/rust-analyzer/crates/span/src/map.rs
@@ -208,7 +208,7 @@ impl RealSpanMap {
         Span {
             range: range - offset,
             anchor: SpanAnchor { file_id: self.file_id, ast_id },
-            ctx: SyntaxContextId::ROOT,
+            ctx: SyntaxContextId::root(self.file_id.edition()),
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/stdx/Cargo.toml b/src/tools/rust-analyzer/crates/stdx/Cargo.toml
index bf0d6df9ad8..1ebb48c577a 100644
--- a/src/tools/rust-analyzer/crates/stdx/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/stdx/Cargo.toml
@@ -23,7 +23,7 @@ itertools.workspace = true
 
 [target.'cfg(windows)'.dependencies]
 miow = "0.6.0"
-windows-sys = { version = "0.52", features = ["Win32_Foundation"] }
+windows-sys = { version = "0.59", features = ["Win32_Foundation"] }
 
 [features]
 # Uncomment to enable for the whole crate graph
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 ed8b1908d60..19801c49e43 100644
--- a/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs
@@ -1,6 +1,6 @@
 //! Conversions between [`SyntaxNode`] and [`tt::TokenTree`].
 
-use std::fmt;
+use std::{fmt, hash::Hash};
 
 use intern::Symbol;
 use rustc_hash::{FxHashMap, FxHashSet};
@@ -58,7 +58,7 @@ pub mod dummy_test_span_utils {
             ),
             ast_id: span::ROOT_ERASED_FILE_AST_ID,
         },
-        ctx: SyntaxContextId::ROOT,
+        ctx: SyntaxContextId::root(Edition::CURRENT),
     };
 
     pub struct DummyTestSpanMap;
@@ -74,7 +74,7 @@ pub mod dummy_test_span_utils {
                     ),
                     ast_id: span::ROOT_ERASED_FILE_AST_ID,
                 },
-                ctx: SyntaxContextId::ROOT,
+                ctx: SyntaxContextId::root(Edition::CURRENT),
             }
         }
     }
@@ -141,15 +141,16 @@ where
 pub fn token_tree_to_syntax_node<Ctx>(
     tt: &tt::TopSubtree<SpanData<Ctx>>,
     entry_point: parser::TopEntryPoint,
-    edition: parser::Edition,
+    span_to_edition: &mut dyn FnMut(Ctx) -> Edition,
+    top_edition: Edition,
 ) -> (Parse<SyntaxNode>, SpanMap<Ctx>)
 where
-    SpanData<Ctx>: Copy + fmt::Debug,
-    Ctx: PartialEq,
+    Ctx: Copy + fmt::Debug + PartialEq + PartialEq + Eq + Hash,
 {
     let buffer = tt.view().strip_invisible();
-    let parser_input = to_parser_input(edition, buffer);
-    let parser_output = entry_point.parse(&parser_input, edition);
+    let parser_input = to_parser_input(buffer, span_to_edition);
+    // It matters what edition we parse with even when we escape all identifiers correctly.
+    let parser_output = entry_point.parse(&parser_input, top_edition);
     let mut tree_sink = TtTreeSink::new(buffer.cursor());
     for event in parser_output.iter() {
         match event {
diff --git a/src/tools/rust-analyzer/crates/syntax-bridge/src/to_parser_input.rs b/src/tools/rust-analyzer/crates/syntax-bridge/src/to_parser_input.rs
index 1bbb05f5507..0dcb2be316c 100644
--- a/src/tools/rust-analyzer/crates/syntax-bridge/src/to_parser_input.rs
+++ b/src/tools/rust-analyzer/crates/syntax-bridge/src/to_parser_input.rs
@@ -2,17 +2,20 @@
 //! format that works for our parser.
 
 use std::fmt;
+use std::hash::Hash;
 
-use span::Edition;
+use rustc_hash::FxHashMap;
+use span::{Edition, SpanData};
 use syntax::{SyntaxKind, SyntaxKind::*, T};
 
-pub fn to_parser_input<S: Copy + fmt::Debug>(
-    edition: Edition,
-    buffer: tt::TokenTreesView<'_, S>,
+pub fn to_parser_input<Ctx: Copy + fmt::Debug + PartialEq + Eq + Hash>(
+    buffer: tt::TokenTreesView<'_, SpanData<Ctx>>,
+    span_to_edition: &mut dyn FnMut(Ctx) -> Edition,
 ) -> parser::Input {
     let mut res = parser::Input::default();
 
     let mut current = buffer.cursor();
+    let mut syntax_context_to_edition_cache = FxHashMap::default();
 
     while !current.eof() {
         let tt = current.token_tree();
@@ -57,20 +60,25 @@ pub fn to_parser_input<S: Copy + fmt::Debug>(
                             res.was_joint();
                         }
                     }
-                    tt::Leaf::Ident(ident) => match ident.sym.as_str() {
-                        "_" => res.push(T![_]),
-                        i if i.starts_with('\'') => res.push(LIFETIME_IDENT),
-                        _ if ident.is_raw.yes() => res.push(IDENT),
-                        text => match SyntaxKind::from_keyword(text, edition) {
-                            Some(kind) => res.push(kind),
-                            None => {
-                                let contextual_keyword =
-                                    SyntaxKind::from_contextual_keyword(text, edition)
-                                        .unwrap_or(SyntaxKind::IDENT);
-                                res.push_ident(contextual_keyword);
-                            }
-                        },
-                    },
+                    tt::Leaf::Ident(ident) => {
+                        let edition = *syntax_context_to_edition_cache
+                            .entry(ident.span.ctx)
+                            .or_insert_with(|| span_to_edition(ident.span.ctx));
+                        match ident.sym.as_str() {
+                            "_" => res.push(T![_]),
+                            i if i.starts_with('\'') => res.push(LIFETIME_IDENT),
+                            _ if ident.is_raw.yes() => res.push(IDENT),
+                            text => match SyntaxKind::from_keyword(text, edition) {
+                                Some(kind) => res.push(kind),
+                                None => {
+                                    let contextual_keyword =
+                                        SyntaxKind::from_contextual_keyword(text, edition)
+                                            .unwrap_or(SyntaxKind::IDENT);
+                                    res.push_ident(contextual_keyword);
+                                }
+                            },
+                        }
+                    }
                     tt::Leaf::Punct(punct) => {
                         let kind = SyntaxKind::from_char(punct.char)
                             .unwrap_or_else(|| panic!("{punct:#?} is not a valid punct"));
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs
index de40d638be3..579f3ba8b4f 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs
@@ -153,8 +153,8 @@ impl<N: AstNode + Clone> AstNodeEdit for N {}
 #[test]
 fn test_increase_indent() {
     let arm_list = {
-        let arm = make::match_arm(iter::once(make::wildcard_pat().into()), None, make::expr_unit());
-        make::match_arm_list(vec![arm.clone(), arm])
+        let arm = make::match_arm(make::wildcard_pat().into(), None, make::ext::expr_unit());
+        make::match_arm_list([arm.clone(), arm])
     };
     assert_eq!(
         arm_list.syntax().to_string(),
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs
index 9466755576b..93faeb40c32 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs
@@ -10,7 +10,7 @@ use crate::{
         FormatArgsArg, FormatArgsExpr, MacroDef, Static, TokenTree,
     },
     AstToken,
-    SyntaxKind::*,
+    SyntaxKind::{self, *},
     SyntaxNode, SyntaxToken, T,
 };
 
@@ -50,6 +50,27 @@ impl From<ast::IfExpr> for ElseBranch {
     }
 }
 
+impl AstNode for ElseBranch {
+    fn can_cast(kind: SyntaxKind) -> bool {
+        ast::BlockExpr::can_cast(kind) || ast::IfExpr::can_cast(kind)
+    }
+
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        if let Some(block_expr) = ast::BlockExpr::cast(syntax.clone()) {
+            Some(Self::Block(block_expr))
+        } else {
+            ast::IfExpr::cast(syntax).map(Self::IfExpr)
+        }
+    }
+
+    fn syntax(&self) -> &SyntaxNode {
+        match self {
+            ElseBranch::Block(block_expr) => block_expr.syntax(),
+            ElseBranch::IfExpr(if_expr) => if_expr.syntax(),
+        }
+    }
+}
+
 impl ast::IfExpr {
     pub fn condition(&self) -> Option<ast::Expr> {
         // If the condition is a BlockExpr, check if the then body is missing.
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
index 282cbc4b3a4..dca231604fa 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
@@ -63,6 +63,9 @@ pub mod ext {
         Some(expr)
     }
 
+    pub fn expr_unit() -> ast::Expr {
+        expr_tuple([]).into()
+    }
     pub fn expr_unreachable() -> ast::Expr {
         expr_from_text("unreachable!()")
     }
@@ -546,10 +549,6 @@ pub fn hacky_block_expr(
     ast_from_text(&format!("fn f() {buf}"))
 }
 
-pub fn expr_unit() -> ast::Expr {
-    expr_from_text("()")
-}
-
 pub fn expr_literal(text: &str) -> ast::Literal {
     assert_eq!(text.trim(), text);
     ast_from_text(&format!("fn f() {{ let _ = {text}; }}"))
@@ -559,8 +558,8 @@ pub fn expr_const_value(text: &str) -> ast::ConstArg {
     ast_from_text(&format!("trait Foo<const N: usize = {text}> {{}}"))
 }
 
-pub fn expr_empty_block() -> ast::Expr {
-    expr_from_text("{}")
+pub fn expr_empty_block() -> ast::BlockExpr {
+    ast_from_text("const C: () = {};")
 }
 pub fn expr_path(path: ast::Path) -> ast::Expr {
     expr_from_text(&path.to_string())
@@ -600,14 +599,14 @@ pub fn expr_try(expr: ast::Expr) -> ast::Expr {
 pub fn expr_await(expr: ast::Expr) -> ast::Expr {
     expr_from_text(&format!("{expr}.await"))
 }
-pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Expr {
+pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::MatchExpr {
     expr_from_text(&format!("match {expr} {match_arm_list}"))
 }
 pub fn expr_if(
     condition: ast::Expr,
     then_branch: ast::BlockExpr,
     else_branch: Option<ast::ElseBranch>,
-) -> ast::Expr {
+) -> ast::IfExpr {
     let else_branch = match else_branch {
         Some(ast::ElseBranch::Block(block)) => format!("else {block}"),
         Some(ast::ElseBranch::IfExpr(if_expr)) => format!("else {if_expr}"),
@@ -623,7 +622,7 @@ pub fn expr_loop(block: ast::BlockExpr) -> ast::Expr {
     expr_from_text(&format!("loop {block}"))
 }
 
-pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::Expr {
+pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::PrefixExpr {
     let token = token(op);
     expr_from_text(&format!("{token}{expr}"))
 }
@@ -656,14 +655,14 @@ pub fn expr_field(receiver: ast::Expr, field: &str) -> ast::Expr {
 pub fn expr_paren(expr: ast::Expr) -> ast::Expr {
     expr_from_text(&format!("({expr})"))
 }
-pub fn expr_tuple(elements: impl IntoIterator<Item = ast::Expr>) -> ast::Expr {
+pub fn expr_tuple(elements: impl IntoIterator<Item = ast::Expr>) -> ast::TupleExpr {
     let expr = elements.into_iter().format(", ");
     expr_from_text(&format!("({expr})"))
 }
 pub fn expr_assignment(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
     expr_from_text(&format!("{lhs} = {rhs}"))
 }
-fn expr_from_text(text: &str) -> ast::Expr {
+fn expr_from_text<E: Into<ast::Expr> + AstNode>(text: &str) -> E {
     ast_from_text(&format!("const C: () = {text};"))
 }
 pub fn expr_let(pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr {
@@ -788,15 +787,21 @@ pub fn path_pat(path: ast::Path) -> ast::Pat {
     }
 }
 
-pub fn match_arm(
-    pats: impl IntoIterator<Item = ast::Pat>,
-    guard: Option<ast::Expr>,
-    expr: ast::Expr,
-) -> ast::MatchArm {
-    let pats_str = pats.into_iter().join(" | ");
+/// Returns a `Pat` if the path has just one segment, an `OrPat` otherwise.
+pub fn or_pat(pats: impl IntoIterator<Item = ast::Pat>, leading_pipe: bool) -> ast::Pat {
+    let leading_pipe = if leading_pipe { "| " } else { "" };
+    let pats = pats.into_iter().join(" | ");
+
+    return from_text(&format!("{leading_pipe}{pats}"));
+    fn from_text(text: &str) -> ast::Pat {
+        ast_from_text(&format!("fn f({text}: ())"))
+    }
+}
+
+pub fn match_arm(pat: ast::Pat, guard: Option<ast::MatchGuard>, expr: ast::Expr) -> ast::MatchArm {
     return match guard {
-        Some(guard) => from_text(&format!("{pats_str} if {guard} => {expr}")),
-        None => from_text(&format!("{pats_str} => {expr}")),
+        Some(guard) => from_text(&format!("{pat} {guard} => {expr}")),
+        None => from_text(&format!("{pat} => {expr}")),
     };
 
     fn from_text(text: &str) -> ast::MatchArm {
@@ -817,6 +822,14 @@ pub fn match_arm_with_guard(
     }
 }
 
+pub fn match_guard(condition: ast::Expr) -> ast::MatchGuard {
+    return from_text(&format!("if {condition}"));
+
+    fn from_text(text: &str) -> ast::MatchGuard {
+        ast_from_text(&format!("fn f() {{ match () {{() {text} => () }}"))
+    }
+}
+
 pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::MatchArmList {
     let arms_str = arms.into_iter().fold(String::new(), |mut acc, arm| {
         let needs_comma = arm.expr().is_none_or(|it| !it.is_block_like());
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
index 81c7e15bcbc..56f94b965e3 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
@@ -185,6 +185,14 @@ impl ast::Attr {
         Some((self.simple_name()?, tt))
     }
 
+    pub fn as_simple_path(&self) -> Option<ast::Path> {
+        let meta = self.meta()?;
+        if meta.eq_token().is_some() || meta.token_tree().is_some() {
+            return None;
+        }
+        self.path()
+    }
+
     pub fn simple_name(&self) -> Option<SmolStr> {
         let path = self.meta()?.path()?;
         match (path.segment(), path.qualifier()) {
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 bea6bfeafcf..572622db544 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
@@ -1,6 +1,9 @@
 //! Wrappers over [`make`] constructors
 use crate::{
-    ast::{self, make, HasGenericParams, HasName, HasTypeBounds, HasVisibility},
+    ast::{
+        self, make, HasArgList, HasGenericArgs, HasGenericParams, HasName, HasTypeBounds,
+        HasVisibility,
+    },
     syntax_editor::SyntaxMappingBuilder,
     AstNode, NodeOrToken, SyntaxKind, SyntaxNode, SyntaxToken,
 };
@@ -12,6 +15,14 @@ impl SyntaxFactory {
         make::name(name).clone_for_update()
     }
 
+    pub fn name_ref(&self, name: &str) -> ast::NameRef {
+        make::name_ref(name).clone_for_update()
+    }
+
+    pub fn lifetime(&self, text: &str) -> ast::Lifetime {
+        make::lifetime(text).clone_for_update()
+    }
+
     pub fn ty(&self, text: &str) -> ast::Type {
         make::ty(text).clone_for_update()
     }
@@ -24,6 +35,20 @@ impl SyntaxFactory {
         ast
     }
 
+    pub fn ty_path(&self, path: ast::Path) -> ast::PathType {
+        let ast::Type::PathType(ast) = make::ty_path(path.clone()).clone_for_update() else {
+            unreachable!()
+        };
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(path.syntax().clone(), ast.path().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
     pub fn type_param(
         &self,
         name: ast::Name,
@@ -46,6 +71,71 @@ impl SyntaxFactory {
         ast
     }
 
+    pub fn path_segment(&self, name_ref: ast::NameRef) -> ast::PathSegment {
+        let ast = make::path_segment(name_ref.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(name_ref.syntax().clone(), ast.name_ref().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn path_segment_generics(
+        &self,
+        name_ref: ast::NameRef,
+        generic_arg_list: ast::GenericArgList,
+    ) -> ast::PathSegment {
+        let ast::Type::PathType(path) = make::ty(&format!("{name_ref}{generic_arg_list}")) else {
+            unreachable!();
+        };
+
+        let ast = path.path().unwrap().segment().unwrap().clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(name_ref.syntax().clone(), ast.name_ref().unwrap().syntax().clone());
+            builder.map_node(
+                generic_arg_list.syntax().clone(),
+                ast.generic_arg_list().unwrap().syntax().clone(),
+            );
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn path_unqualified(&self, segment: ast::PathSegment) -> ast::Path {
+        let ast = make::path_unqualified(segment.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(segment.syntax().clone(), ast.segment().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn path_from_segments(
+        &self,
+        segments: impl IntoIterator<Item = ast::PathSegment>,
+        is_abs: bool,
+    ) -> ast::Path {
+        let (segments, input) = iterator_input(segments);
+        let ast = make::path_from_segments(segments, is_abs).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_children(input.into_iter(), ast.segments().map(|it| it.syntax().clone()));
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
     pub fn ident_pat(&self, ref_: bool, mut_: bool, name: ast::Name) -> ast::IdentPat {
         let ast = make::ident_pat(ref_, mut_, name.clone()).clone_for_update();
 
@@ -58,6 +148,32 @@ impl SyntaxFactory {
         ast
     }
 
+    pub fn wildcard_pat(&self) -> ast::WildcardPat {
+        make::wildcard_pat().clone_for_update()
+    }
+
+    pub fn literal_pat(&self, text: &str) -> ast::LiteralPat {
+        make::literal_pat(text).clone_for_update()
+    }
+
+    pub fn tuple_struct_pat(
+        &self,
+        path: ast::Path,
+        fields: impl IntoIterator<Item = ast::Pat>,
+    ) -> ast::TupleStructPat {
+        let (fields, input) = iterator_input(fields);
+        let ast = make::tuple_struct_pat(path.clone(), fields).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(path.syntax().clone(), ast.path().unwrap().syntax().clone());
+            builder.map_children(input.into_iter(), ast.fields().map(|it| it.syntax().clone()));
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
     pub fn block_expr(
         &self,
         statements: impl IntoIterator<Item = ast::Stmt>,
@@ -95,7 +211,20 @@ impl SyntaxFactory {
     }
 
     pub fn expr_empty_block(&self) -> ast::BlockExpr {
-        ast::BlockExpr { syntax: make::expr_empty_block().syntax().clone_for_update() }
+        make::expr_empty_block().clone_for_update()
+    }
+
+    pub fn expr_tuple(&self, fields: impl IntoIterator<Item = ast::Expr>) -> ast::TupleExpr {
+        let (fields, input) = iterator_input(fields);
+        let ast = make::expr_tuple(fields).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_children(input.into_iter(), ast.fields().map(|it| it.syntax().clone()));
+            builder.finish(&mut mapping);
+        }
+
+        ast
     }
 
     pub fn expr_bin(&self, lhs: ast::Expr, op: ast::BinaryOp, rhs: ast::Expr) -> ast::BinExpr {
@@ -115,6 +244,10 @@ impl SyntaxFactory {
         ast
     }
 
+    pub fn expr_literal(&self, text: &str) -> ast::Literal {
+        make::expr_literal(text).clone_for_update()
+    }
+
     pub fn expr_path(&self, path: ast::Path) -> ast::Expr {
         let ast::Expr::PathExpr(ast) = make::expr_path(path.clone()).clone_for_update() else {
             unreachable!()
@@ -129,6 +262,49 @@ impl SyntaxFactory {
         ast.into()
     }
 
+    pub fn expr_prefix(&self, op: SyntaxKind, expr: ast::Expr) -> ast::PrefixExpr {
+        let ast = make::expr_prefix(op, expr.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn expr_call(&self, expr: ast::Expr, arg_list: ast::ArgList) -> ast::CallExpr {
+        // FIXME: `make::expr_call`` should return a `CallExpr`, not just an `Expr`
+        let ast::Expr::CallExpr(ast) =
+            make::expr_call(expr.clone(), arg_list.clone()).clone_for_update()
+        else {
+            unreachable!()
+        };
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone());
+            builder.map_node(arg_list.syntax().clone(), ast.arg_list().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn arg_list(&self, args: impl IntoIterator<Item = ast::Expr>) -> ast::ArgList {
+        let (args, input) = iterator_input(args);
+        let ast = make::arg_list(args).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax.clone());
+            builder.map_children(input.into_iter(), ast.args().map(|it| it.syntax().clone()));
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
     pub fn expr_ref(&self, expr: ast::Expr, exclusive: bool) -> ast::Expr {
         let ast::Expr::RefExpr(ast) = make::expr_ref(expr.clone(), exclusive).clone_for_update()
         else {
@@ -160,6 +336,125 @@ impl SyntaxFactory {
         ast
     }
 
+    pub fn expr_if(
+        &self,
+        condition: ast::Expr,
+        then_branch: ast::BlockExpr,
+        else_branch: Option<ast::ElseBranch>,
+    ) -> ast::IfExpr {
+        let ast = make::expr_if(condition.clone(), then_branch.clone(), else_branch.clone())
+            .clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(condition.syntax().clone(), ast.condition().unwrap().syntax().clone());
+            builder.map_node(
+                then_branch.syntax().clone(),
+                ast.then_branch().unwrap().syntax().clone(),
+            );
+
+            if let Some(else_branch) = else_branch {
+                builder.map_node(
+                    else_branch.syntax().clone(),
+                    ast.else_branch().unwrap().syntax().clone(),
+                );
+            }
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn expr_let(&self, pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr {
+        let ast = make::expr_let(pattern.clone(), expr.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(pattern.syntax().clone(), ast.pat().unwrap().syntax().clone());
+            builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn expr_stmt(&self, expr: ast::Expr) -> ast::ExprStmt {
+        let ast = make::expr_stmt(expr.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn expr_match(&self, expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::MatchExpr {
+        let ast = make::expr_match(expr.clone(), match_arm_list.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone());
+            builder.map_node(
+                match_arm_list.syntax().clone(),
+                ast.match_arm_list().unwrap().syntax().clone(),
+            );
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn match_arm(
+        &self,
+        pat: ast::Pat,
+        guard: Option<ast::MatchGuard>,
+        expr: ast::Expr,
+    ) -> ast::MatchArm {
+        let ast = make::match_arm(pat.clone(), guard.clone(), expr.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(pat.syntax().clone(), ast.pat().unwrap().syntax().clone());
+            if let Some(guard) = guard {
+                builder.map_node(guard.syntax().clone(), ast.guard().unwrap().syntax().clone());
+            }
+            builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn match_guard(&self, condition: ast::Expr) -> ast::MatchGuard {
+        let ast = make::match_guard(condition.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(condition.syntax().clone(), ast.condition().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn match_arm_list(
+        &self,
+        match_arms: impl IntoIterator<Item = ast::MatchArm>,
+    ) -> ast::MatchArmList {
+        let (match_arms, input) = iterator_input(match_arms);
+        let ast = make::match_arm_list(match_arms).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_children(input.into_iter(), ast.arms().map(|it| it.syntax().clone()));
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
     pub fn let_stmt(
         &self,
         pattern: ast::Pat,
@@ -185,6 +480,30 @@ impl SyntaxFactory {
         ast
     }
 
+    pub fn type_arg(&self, ty: ast::Type) -> ast::TypeArg {
+        let ast = make::type_arg(ty.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(ty.syntax().clone(), ast.ty().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn lifetime_arg(&self, lifetime: ast::Lifetime) -> ast::LifetimeArg {
+        let ast = make::lifetime_arg(lifetime.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(lifetime.syntax().clone(), ast.lifetime().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
     pub fn item_const(
         &self,
         visibility: Option<ast::Visibility>,
@@ -252,12 +571,17 @@ impl SyntaxFactory {
         ast
     }
 
-    pub fn turbofish_generic_arg_list(
+    pub fn generic_arg_list(
         &self,
         generic_args: impl IntoIterator<Item = ast::GenericArg>,
+        is_turbo: bool,
     ) -> ast::GenericArgList {
         let (generic_args, input) = iterator_input(generic_args);
-        let ast = make::turbofish_generic_arg_list(generic_args.clone()).clone_for_update();
+        let ast = if is_turbo {
+            make::turbofish_generic_arg_list(generic_args).clone_for_update()
+        } else {
+            make::generic_arg_list(generic_args).clone_for_update()
+        };
 
         if let Some(mut mapping) = self.mappings() {
             let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
@@ -503,11 +827,41 @@ impl SyntaxFactory {
         make::token(kind)
     }
 
-    pub fn whitespace(&self, text: &str) -> ast::SyntaxToken {
+    pub fn whitespace(&self, text: &str) -> SyntaxToken {
         make::tokens::whitespace(text)
     }
 }
 
+// `ext` constructors
+impl SyntaxFactory {
+    pub fn ident_path(&self, ident: &str) -> ast::Path {
+        self.path_unqualified(self.path_segment(self.name_ref(ident)))
+    }
+
+    pub fn expr_unit(&self) -> ast::Expr {
+        self.expr_tuple([]).into()
+    }
+
+    pub fn ty_option(&self, t: ast::Type) -> ast::PathType {
+        let generic_arg_list = self.generic_arg_list([self.type_arg(t).into()], false);
+        let path = self.path_unqualified(
+            self.path_segment_generics(self.name_ref("Option"), generic_arg_list),
+        );
+
+        self.ty_path(path)
+    }
+
+    pub fn ty_result(&self, t: ast::Type, e: ast::Type) -> ast::PathType {
+        let generic_arg_list =
+            self.generic_arg_list([self.type_arg(t).into(), self.type_arg(e).into()], false);
+        let path = self.path_unqualified(
+            self.path_segment_generics(self.name_ref("Result"), generic_arg_list),
+        );
+
+        self.ty_path(path)
+    }
+}
+
 // We need to collect `input` here instead of taking `impl IntoIterator + Clone`,
 // because if we took `impl IntoIterator + Clone`, that could be something like an
 // `Iterator::map` with a closure that also makes use of a `SyntaxFactory` constructor.
diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs
index 992a847663a..b82181ae13a 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs
@@ -335,7 +335,7 @@ mod tests {
     #[test]
     fn basic_usage() {
         let root = make::match_arm(
-            [make::wildcard_pat().into()],
+            make::wildcard_pat().into(),
             None,
             make::expr_tuple([
                 make::expr_bin_op(
@@ -344,7 +344,8 @@ mod tests {
                     make::expr_literal("2").into(),
                 ),
                 make::expr_literal("true").into(),
-            ]),
+            ])
+            .into(),
         );
 
         let to_wrap = root.syntax().descendants().find_map(ast::TupleExpr::cast).unwrap();
@@ -549,7 +550,7 @@ mod tests {
             None,
             None,
             make::param_list(None, []),
-            make::block_expr([], Some(make::expr_unit())),
+            make::block_expr([], Some(make::ext::expr_unit())),
             Some(make::ret_type(make::ty_unit())),
             false,
             false,
diff --git a/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml b/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml
index c860e7b1183..95f4cb9d67e 100644
--- a/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml
@@ -2,6 +2,8 @@
 name = "test-fixture"
 version = "0.0.0"
 rust-version.workspace = true
+description = "Test fixtures for rust-analyzer."
+
 edition.workspace = true
 license.workspace = true
 authors.workspace = true
diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
index 0e72d796875..866379d940e 100644
--- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
@@ -30,7 +30,9 @@ pub const WORKSPACE: base_db::SourceRootId = base_db::SourceRootId(0);
 
 pub trait WithFixture: Default + ExpandDatabase + SourceRootDatabase + 'static {
     #[track_caller]
-    fn with_single_file(ra_fixture: &str) -> (Self, EditionedFileId) {
+    fn with_single_file(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    ) -> (Self, EditionedFileId) {
         let fixture = ChangeFixture::parse(ra_fixture);
         let mut db = Self::default();
         fixture.change.apply(&mut db);
@@ -39,7 +41,9 @@ pub trait WithFixture: Default + ExpandDatabase + SourceRootDatabase + 'static {
     }
 
     #[track_caller]
-    fn with_many_files(ra_fixture: &str) -> (Self, Vec<EditionedFileId>) {
+    fn with_many_files(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    ) -> (Self, Vec<EditionedFileId>) {
         let fixture = ChangeFixture::parse(ra_fixture);
         let mut db = Self::default();
         fixture.change.apply(&mut db);
@@ -48,7 +52,7 @@ pub trait WithFixture: Default + ExpandDatabase + SourceRootDatabase + 'static {
     }
 
     #[track_caller]
-    fn with_files(ra_fixture: &str) -> Self {
+    fn with_files(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> Self {
         let fixture = ChangeFixture::parse(ra_fixture);
         let mut db = Self::default();
         fixture.change.apply(&mut db);
@@ -58,7 +62,7 @@ pub trait WithFixture: Default + ExpandDatabase + SourceRootDatabase + 'static {
 
     #[track_caller]
     fn with_files_extra_proc_macros(
-        ra_fixture: &str,
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
         proc_macros: Vec<(String, ProcMacro)>,
     ) -> Self {
         let fixture = ChangeFixture::parse_with_proc_macros(ra_fixture, proc_macros);
@@ -69,21 +73,23 @@ pub trait WithFixture: Default + ExpandDatabase + SourceRootDatabase + 'static {
     }
 
     #[track_caller]
-    fn with_position(ra_fixture: &str) -> (Self, FilePosition) {
+    fn with_position(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (Self, FilePosition) {
         let (db, file_id, range_or_offset) = Self::with_range_or_offset(ra_fixture);
         let offset = range_or_offset.expect_offset();
         (db, FilePosition { file_id, offset })
     }
 
     #[track_caller]
-    fn with_range(ra_fixture: &str) -> (Self, FileRange) {
+    fn with_range(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (Self, FileRange) {
         let (db, file_id, range_or_offset) = Self::with_range_or_offset(ra_fixture);
         let range = range_or_offset.expect_range();
         (db, FileRange { file_id, range })
     }
 
     #[track_caller]
-    fn with_range_or_offset(ra_fixture: &str) -> (Self, EditionedFileId, RangeOrOffset) {
+    fn with_range_or_offset(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    ) -> (Self, EditionedFileId, RangeOrOffset) {
         let fixture = ChangeFixture::parse(ra_fixture);
         let mut db = Self::default();
         fixture.change.apply(&mut db);
@@ -116,12 +122,12 @@ pub struct ChangeFixture {
 const SOURCE_ROOT_PREFIX: &str = "/";
 
 impl ChangeFixture {
-    pub fn parse(ra_fixture: &str) -> ChangeFixture {
+    pub fn parse(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> ChangeFixture {
         Self::parse_with_proc_macros(ra_fixture, Vec::new())
     }
 
     pub fn parse_with_proc_macros(
-        ra_fixture: &str,
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
         mut proc_macro_defs: Vec<(String, ProcMacro)>,
     ) -> ChangeFixture {
         let FixtureWithProjectMeta {
@@ -376,8 +382,8 @@ impl ChangeFixture {
     }
 }
 
-fn default_test_proc_macros() -> [(String, ProcMacro); 8] {
-    [
+fn default_test_proc_macros() -> Box<[(String, ProcMacro)]> {
+    Box::new([
         (
             r#"
 #[proc_macro_attribute]
@@ -498,7 +504,22 @@ pub fn issue_17479(input: TokenStream) -> TokenStream {
                 disabled: false,
             },
         ),
-    ]
+        (
+            r#"
+#[proc_macro_attribute]
+pub fn issue_18898(_attr: TokenStream, input: TokenStream) -> TokenStream {
+    input
+}
+"#
+            .into(),
+            ProcMacro {
+                name: Symbol::intern("issue_18898"),
+                kind: ProcMacroKind::Bang,
+                expander: sync::Arc::new(Issue18898ProcMacroExpander),
+                disabled: false,
+            },
+        ),
+    ])
 }
 
 fn filter_test_proc_macros(
@@ -801,3 +822,54 @@ impl ProcMacroExpander for Issue17479ProcMacroExpander {
         })
     }
 }
+
+// Reads ident type within string quotes, for issue #17479.
+#[derive(Debug)]
+struct Issue18898ProcMacroExpander;
+impl ProcMacroExpander for Issue18898ProcMacroExpander {
+    fn expand(
+        &self,
+        subtree: &TopSubtree,
+        _: Option<&TopSubtree>,
+        _: &Env,
+        def_site: Span,
+        _: Span,
+        _: Span,
+        _: Option<String>,
+    ) -> Result<TopSubtree, ProcMacroExpansionError> {
+        let span = subtree
+            .token_trees()
+            .flat_tokens()
+            .last()
+            .ok_or_else(|| ProcMacroExpansionError::Panic("malformed input".to_owned()))?
+            .first_span();
+        let overly_long_subtree = quote! {span =>
+            {
+                let a = 5;
+                let a = 5;
+                let a = 5;
+                let a = 5;
+                let a = 5;
+                let a = 5;
+                let a = 5;
+                let a = 5;
+                let a = 5;
+                let a = 5;
+                let a = 5;
+                let a = 5;
+                let a = 5;
+                let a = 5;
+                let a = 5;
+                let a = 5;
+                let a = 5;
+                let a = 5;
+                let a = 5;
+            }
+        };
+        Ok(quote! { def_site =>
+            fn foo() {
+                #overly_long_subtree
+            }
+        })
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
index 54c9db7aacc..7fe26d53bf2 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
@@ -168,7 +168,7 @@ impl FixtureWithProjectMeta {
     /// That will set toolchain to nightly and include predefined proc macros and a subset of
     /// `libcore` into the fixture, see `minicore.rs` for what's available. Note that toolchain
     /// defaults to stable.
-    pub fn parse(ra_fixture: &str) -> Self {
+    pub fn parse(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> Self {
         let fixture = trim_indent(ra_fixture);
         let mut fixture = fixture.as_str();
         let mut toolchain = None;
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 4a2346193b4..fd06736a252 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
@@ -32,7 +32,7 @@
 //!     error: fmt
 //!     fmt: option, result, transmute, coerce_unsized, copy, clone, derive
 //!     fn: tuple
-//!     from: sized
+//!     from: sized, result
 //!     future: pin
 //!     coroutine: pin
 //!     dispatch_from_dyn: unsize, pin
@@ -332,6 +332,25 @@ pub mod convert {
             t
         }
     }
+
+    pub trait TryFrom<T>: Sized {
+        type Error;
+        fn try_from(value: T) -> Result<Self, Self::Error>;
+    }
+    pub trait TryInto<T>: Sized {
+        type Error;
+        fn try_into(self) -> Result<T, Self::Error>;
+    }
+
+    impl<T, U> TryInto<U> for T
+    where
+        U: TryFrom<T>,
+    {
+        type Error = U::Error;
+        fn try_into(self) -> Result<U, U::Error> {
+            U::try_from(self)
+        }
+    }
     // endregion:from
 
     // region:as_ref
@@ -1510,7 +1529,7 @@ pub mod iter {
             impl<T, const N: usize> IntoIterator for [T; N] {
                 type Item = T;
                 type IntoIter = IntoIter<T, N>;
-                fn into_iter(self) -> I {
+                fn into_iter(self) -> Self::IntoIter {
                     IntoIter { data: self, range: IndexRange { start: 0, end: loop {} } }
                 }
             }
@@ -1520,6 +1539,29 @@ pub mod iter {
                     loop {}
                 }
             }
+            pub struct Iter<'a, T> {
+                slice: &'a [T],
+            }
+            impl<'a, T> IntoIterator for &'a [T; N] {
+                type Item = &'a T;
+                type IntoIter = Iter<'a, T>;
+                fn into_iter(self) -> Self::IntoIter {
+                    loop {}
+                }
+            }
+            impl<'a, T> IntoIterator for &'a [T] {
+                type Item = &'a T;
+                type IntoIter = Iter<'a, T>;
+                fn into_iter(self) -> Self::IntoIter {
+                    loop {}
+                }
+            }
+            impl<'a, T> Iterator for Iter<'a, T> {
+                type Item = &'a T;
+                fn next(&mut self) -> Option<T> {
+                    loop {}
+                }
+            }
         }
         pub use self::collect::IntoIterator;
     }
@@ -1532,6 +1574,15 @@ pub mod str {
     pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str {
         ""
     }
+    pub trait FromStr: Sized {
+        type Err;
+        fn from_str(s: &str) -> Result<Self, Self::Err>;
+    }
+    impl str {
+        pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> {
+            FromStr::from_str(self)
+        }
+    }
 }
 // endregion:str
 
@@ -1791,7 +1842,7 @@ pub mod prelude {
             cmp::{Eq, PartialEq},                    // :eq
             cmp::{Ord, PartialOrd},                  // :ord
             convert::AsRef,                          // :as_ref
-            convert::{From, Into},                   // :from
+            convert::{From, Into, TryFrom, TryInto}, // :from
             default::Default,                        // :default
             iter::{IntoIterator, Iterator},          // :iterator
             macros::builtin::{derive, derive_const}, // :derive
@@ -1806,6 +1857,7 @@ pub mod prelude {
             option::Option::{self, None, Some},      // :option
             panic,                                   // :panic
             result::Result::{self, Err, Ok},         // :result
+            str::FromStr,                            // :str
         };
     }
 
diff --git a/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml b/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml
index 09296dc6dd5..bc54d7168f0 100644
--- a/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml
@@ -16,7 +16,7 @@ doctest = false
 tracing.workspace = true
 walkdir = "2.3.2"
 crossbeam-channel.workspace = true
-notify = "6.1.1"
+notify = "8.0.0"
 rayon = "1.10.0"
 
 stdx.workspace = true
diff --git a/src/tools/rust-analyzer/docs/dev/README.md b/src/tools/rust-analyzer/docs/dev/README.md
index cd0f49174cd..3ba492e0959 100644
--- a/src/tools/rust-analyzer/docs/dev/README.md
+++ b/src/tools/rust-analyzer/docs/dev/README.md
@@ -154,19 +154,21 @@ There are also several VS Code commands which might be of interest:
 
 * `rust-analyzer: Status` shows some memory-usage statistics.
 
-* `rust-analyzer: Syntax Tree` shows syntax tree of the current file/selection.
-
 * `rust-analyzer: View Hir` shows the HIR expressions within the function containing the cursor.
 
-  You can hover over syntax nodes in the opened text file to see the appropriate
-  rust code that it refers to and the rust editor will also highlight the proper
-  text range.
+* If `rust-analyzer.showSyntaxTree` is enabled in settings, `Rust Syntax Tree: Focus on Rust Syntax Tree View` shows the syntax tree of the current file.
+
+  You can click on nodes in the rust editor to go to the corresponding syntax node.
+
+  You can click on `Reveal Syntax Element` next to a syntax node to go to the corresponding rust code and highlight the proper text range.
 
   If you trigger Go to Definition in the inspected Rust source file,
-  the syntax tree read-only editor should scroll to and select the
+  the syntax tree view should scroll to and select the
   appropriate syntax node token.
 
-  ![demo](https://user-images.githubusercontent.com/36276403/78225773-6636a480-74d3-11ea-9d9f-1c9d42da03b0.png)
+  You can click on `Copy` next to a syntax node to copy a text representation of the node.
+
+  ![demo](https://github.com/user-attachments/assets/2d20ae87-0abf-495f-bee8-54aa2494a00d)
 
 ## Profiling
 
diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
index 21ac3a5a269..a632fc6f5fb 100644
--- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
+++ b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@
 <!---
-lsp/ext.rs hash: 6dd762ae19630ec0
+lsp/ext.rs hash: 2d8604825c458288
 
 If you need to change the above hash to make the test pass, please check if you
 need to adjust this doc as well and ping this issue:
@@ -710,6 +710,23 @@ interface SyntaxTreeParams {
 Returns textual representation of a parse tree for the file/selected region.
 Primarily for debugging, but very useful for all people working on rust-analyzer itself.
 
+## View Syntax Tree
+
+**Method:** `rust-analyzer/viewSyntaxTree`
+
+**Request:**
+
+```typescript
+interface ViewSyntaxTreeParams {
+    textDocument: TextDocumentIdentifier,
+}
+```
+
+**Response:** `string`
+
+Returns json representation of the file's syntax tree.
+Used to create a treeView for debugging and working on rust-analyzer itself.
+
 ## View Hir
 
 **Method:** `rust-analyzer/viewHir`
diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc
index 5b86766aa8e..bd091db58d3 100644
--- a/src/tools/rust-analyzer/docs/user/generated_config.adoc
+++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc
@@ -94,10 +94,10 @@ avoid checking unnecessary things.
 --
 Default:
 ----
-{
-  "miri": null,
-  "debug_assertions": null
-}
+[
+  "debug_assertions",
+  "miri"
+]
 ----
 List of cfg options to enable with the given values.
 
@@ -716,6 +716,11 @@ Whether to show generic type parameter name inlay hints.
 --
 Whether to show implicit drop hints.
 --
+[[rust-analyzer.inlayHints.implicitSizedBoundHints.enable]]rust-analyzer.inlayHints.implicitSizedBoundHints.enable (default: `false`)::
++
+--
+Whether to show inlay hints for the implied type parameter `Sized` bound.
+--
 [[rust-analyzer.inlayHints.lifetimeElisionHints.enable]]rust-analyzer.inlayHints.lifetimeElisionHints.enable (default: `"never"`)::
 +
 --
@@ -1046,10 +1051,25 @@ Show full signature of the callable. Only shows parameters if disabled.
 --
 Show documentation.
 --
-[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `"|<"`)::
+[[rust-analyzer.typing.triggerChars]]rust-analyzer.typing.triggerChars (default: `"=."`)::
++
+--
+Specify the characters allowed to invoke special on typing triggers.
+- typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing expression
+- typing `=` between two expressions adds `;` when in statement position
+- typing `=` to turn an assignment into an equality comparison removes `;` when in expression position
+- typing `.` in a chain method call auto-indents
+- typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the expression
+- typing `{` in a use item adds a closing `}` in the right place
+- typing `>` to complete a return type `->` will insert a whitespace after it
+- typing `<` in a path or type position inserts a closing `>` after the path or type.
+--
+[[rust-analyzer.vfs.extraIncludes]]rust-analyzer.vfs.extraIncludes (default: `[]`)::
 +
 --
-Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`.
+Additional paths to include in the VFS. Generally for code that is
+generated or otherwise managed by a build system outside of Cargo,
+though Cargo might be the eventual consumer.
 --
 [[rust-analyzer.workspace.discoverConfig]]rust-analyzer.workspace.discoverConfig (default: `null`)::
 +
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index 80246bf3fea..8b066377f2b 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -109,11 +109,6 @@
         ],
         "commands": [
             {
-                "command": "rust-analyzer.syntaxTree",
-                "title": "Show Syntax Tree",
-                "category": "rust-analyzer (debug command)"
-            },
-            {
                 "command": "rust-analyzer.viewHir",
                 "title": "View Hir",
                 "category": "rust-analyzer (debug command)"
@@ -289,6 +284,30 @@
                 "category": "rust-analyzer"
             },
             {
+                "command": "rust-analyzer.syntaxTreeReveal",
+                "title": "Reveal Syntax Element",
+                "icon": "$(search)",
+                "category": "rust-analyzer (syntax tree)"
+            },
+            {
+                "command": "rust-analyzer.syntaxTreeCopy",
+                "title": "Copy",
+                "icon": "$(copy)",
+                "category": "rust-analyzer (syntax tree)"
+            },
+            {
+                "command": "rust-analyzer.syntaxTreeHideWhitespace",
+                "title": "Hide Whitespace",
+                "icon": "$(filter)",
+                "category": "rust-analyzer (syntax tree)"
+            },
+            {
+                "command": "rust-analyzer.syntaxTreeShowWhitespace",
+                "title": "Show Whitespace",
+                "icon": "$(filter-filled)",
+                "category": "rust-analyzer (syntax tree)"
+            },
+            {
                 "command": "rust-analyzer.viewMemoryLayout",
                 "title": "View Memory Layout",
                 "category": "rust-analyzer"
@@ -345,6 +364,11 @@
                         "default": true,
                         "type": "boolean"
                     },
+                    "rust-analyzer.showSyntaxTree": {
+                        "markdownDescription": "Whether to show the syntax tree view.",
+                        "default": false,
+                        "type": "boolean"
+                    },
                     "rust-analyzer.testExplorer": {
                         "markdownDescription": "Whether to show the test explorer.",
                         "default": false,
@@ -791,11 +815,14 @@
                 "properties": {
                     "rust-analyzer.cargo.cfgs": {
                         "markdownDescription": "List of cfg options to enable with the given values.",
-                        "default": {
-                            "miri": null,
-                            "debug_assertions": null
-                        },
-                        "type": "object"
+                        "default": [
+                            "debug_assertions",
+                            "miri"
+                        ],
+                        "type": "array",
+                        "items": {
+                            "type": "string"
+                        }
                     }
                 }
             },
@@ -2081,6 +2108,16 @@
             {
                 "title": "inlayHints",
                 "properties": {
+                    "rust-analyzer.inlayHints.implicitSizedBoundHints.enable": {
+                        "markdownDescription": "Whether to show inlay hints for the implied type parameter `Sized` bound.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
                     "rust-analyzer.inlayHints.lifetimeElisionHints.enable": {
                         "markdownDescription": "Whether to show inlay type hints for elided lifetimes in function signatures.",
                         "default": "never",
@@ -2708,9 +2745,9 @@
             {
                 "title": "typing",
                 "properties": {
-                    "rust-analyzer.typing.excludeChars": {
-                        "markdownDescription": "Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`.",
-                        "default": "|<",
+                    "rust-analyzer.typing.triggerChars": {
+                        "markdownDescription": "Specify the characters allowed to invoke special on typing triggers.\n- typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing expression\n- typing `=` between two expressions adds `;` when in statement position\n- typing `=` to turn an assignment into an equality comparison removes `;` when in expression position\n- typing `.` in a chain method call auto-indents\n- typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the expression\n- typing `{` in a use item adds a closing `}` in the right place\n- typing `>` to complete a return type `->` will insert a whitespace after it\n- typing `<` in a path or type position inserts a closing `>` after the path or type.",
+                        "default": "=.",
                         "type": [
                             "null",
                             "string"
@@ -2719,6 +2756,19 @@
                 }
             },
             {
+                "title": "vfs",
+                "properties": {
+                    "rust-analyzer.vfs.extraIncludes": {
+                        "markdownDescription": "Additional paths to include in the VFS. Generally for code that is\ngenerated or otherwise managed by a build system outside of Cargo,\nthough Cargo might be the eventual consumer.",
+                        "default": [],
+                        "type": "array",
+                        "items": {
+                            "type": "string"
+                        }
+                    }
+                }
+            },
+            {
                 "title": "workspace",
                 "properties": {
                     "rust-analyzer.workspace.discoverConfig": {
@@ -2928,17 +2978,6 @@
                 "pattern": "$rustc"
             }
         ],
-        "colors": [
-            {
-                "id": "rust_analyzer.syntaxTreeBorder",
-                "description": "Color of the border displayed in the Rust source code for the selected syntax node (see \"Show Syntax Tree\" command)",
-                "defaults": {
-                    "dark": "#ffffff",
-                    "light": "#b700ff",
-                    "highContrast": "#b700ff"
-                }
-            }
-        ],
         "semanticTokenTypes": [
             {
                 "id": "angle",
@@ -3259,10 +3298,6 @@
         "menus": {
             "commandPalette": [
                 {
-                    "command": "rust-analyzer.syntaxTree",
-                    "when": "inRustProject"
-                },
-                {
                     "command": "rust-analyzer.viewHir",
                     "when": "inRustProject"
                 },
@@ -3344,6 +3379,22 @@
                 },
                 {
                     "command": "rust-analyzer.openWalkthrough"
+                },
+                {
+                    "command": "rust-analyzer.syntaxTreeReveal",
+                    "when": "false"
+                },
+                {
+                    "command": "rust-analyzer.syntaxTreeCopy",
+                    "when": "false"
+                },
+                {
+                    "command": "rust-analyzer.syntaxTreeHideWhitespace",
+                    "when": "false"
+                },
+                {
+                    "command": "rust-analyzer.syntaxTreeShowWhitespace",
+                    "when": "false"
                 }
             ],
             "editor/context": [
@@ -3357,6 +3408,30 @@
                     "when": "inRustProject && editorTextFocus && editorLangId == rust",
                     "group": "navigation@1001"
                 }
+            ],
+            "view/title": [
+                {
+                    "command": "rust-analyzer.syntaxTreeHideWhitespace",
+                    "group": "navigation",
+                    "when": "view == rustSyntaxTree && !rustSyntaxTree.hideWhitespace"
+                },
+                {
+                    "command": "rust-analyzer.syntaxTreeShowWhitespace",
+                    "group": "navigation",
+                    "when": "view == rustSyntaxTree && rustSyntaxTree.hideWhitespace"
+                }
+            ],
+            "view/item/context": [
+                {
+                    "command": "rust-analyzer.syntaxTreeCopy",
+                    "group": "inline",
+                    "when": "view == rustSyntaxTree"
+                },
+                {
+                    "command": "rust-analyzer.syntaxTreeReveal",
+                    "group": "inline",
+                    "when": "view == rustSyntaxTree"
+                }
             ]
         },
         "views": {
@@ -3366,6 +3441,22 @@
                     "name": "Rust Dependencies",
                     "when": "inRustProject && config.rust-analyzer.showDependenciesExplorer"
                 }
+            ],
+            "rustSyntaxTreeContainer": [
+                {
+                    "id": "rustSyntaxTree",
+                    "name": "Rust Syntax Tree",
+                    "when": "inRustProject && config.rust-analyzer.showSyntaxTree"
+                }
+            ]
+        },
+        "viewsContainers": {
+            "activitybar": [
+                {
+                    "id": "rustSyntaxTreeContainer",
+                    "title": "Rust Syntax Tree",
+                    "icon": "$(list-tree)"
+                }
             ]
         },
         "jsonValidation": [
diff --git a/src/tools/rust-analyzer/editors/code/src/ast_inspector.ts b/src/tools/rust-analyzer/editors/code/src/ast_inspector.ts
deleted file mode 100644
index 35b705c477e..00000000000
--- a/src/tools/rust-analyzer/editors/code/src/ast_inspector.ts
+++ /dev/null
@@ -1,216 +0,0 @@
-import * as vscode from "vscode";
-
-import type { Ctx, Disposable } from "./ctx";
-import { type RustEditor, isRustEditor, unwrapUndefinable } from "./util";
-
-// FIXME: consider implementing this via the Tree View API?
-// https://code.visualstudio.com/api/extension-guides/tree-view
-export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, Disposable {
-    private readonly astDecorationType = vscode.window.createTextEditorDecorationType({
-        borderColor: new vscode.ThemeColor("rust_analyzer.syntaxTreeBorder"),
-        borderStyle: "solid",
-        borderWidth: "2px",
-    });
-    private rustEditor: undefined | RustEditor;
-
-    // Lazy rust token range -> syntax tree file range.
-    private readonly rust2Ast = new Lazy(() => {
-        const astEditor = this.findAstTextEditor();
-        if (!this.rustEditor || !astEditor) return undefined;
-
-        const buf: [vscode.Range, vscode.Range][] = [];
-        for (let i = 0; i < astEditor.document.lineCount; ++i) {
-            const astLine = astEditor.document.lineAt(i);
-
-            // Heuristically look for nodes with quoted text (which are token nodes)
-            const isTokenNode = astLine.text.lastIndexOf('"') >= 0;
-            if (!isTokenNode) continue;
-
-            const rustRange = this.parseRustTextRange(this.rustEditor.document, astLine.text);
-            if (!rustRange) continue;
-
-            buf.push([rustRange, this.findAstNodeRange(astLine)]);
-        }
-        return buf;
-    });
-
-    constructor(ctx: Ctx) {
-        ctx.pushExtCleanup(
-            vscode.languages.registerHoverProvider({ scheme: "rust-analyzer" }, this),
-        );
-        ctx.pushExtCleanup(vscode.languages.registerDefinitionProvider({ language: "rust" }, this));
-        vscode.workspace.onDidCloseTextDocument(
-            this.onDidCloseTextDocument,
-            this,
-            ctx.subscriptions,
-        );
-        vscode.workspace.onDidChangeTextDocument(
-            this.onDidChangeTextDocument,
-            this,
-            ctx.subscriptions,
-        );
-        vscode.window.onDidChangeVisibleTextEditors(
-            this.onDidChangeVisibleTextEditors,
-            this,
-            ctx.subscriptions,
-        );
-    }
-    dispose() {
-        this.setRustEditor(undefined);
-    }
-
-    private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
-        if (
-            this.rustEditor &&
-            event.document.uri.toString() === this.rustEditor.document.uri.toString()
-        ) {
-            this.rust2Ast.reset();
-        }
-    }
-
-    private onDidCloseTextDocument(doc: vscode.TextDocument) {
-        if (this.rustEditor && doc.uri.toString() === this.rustEditor.document.uri.toString()) {
-            this.setRustEditor(undefined);
-        }
-    }
-
-    private onDidChangeVisibleTextEditors(editors: readonly vscode.TextEditor[]) {
-        if (!this.findAstTextEditor()) {
-            this.setRustEditor(undefined);
-            return;
-        }
-        this.setRustEditor(editors.find(isRustEditor));
-    }
-
-    private findAstTextEditor(): undefined | vscode.TextEditor {
-        return vscode.window.visibleTextEditors.find(
-            (it) => it.document.uri.scheme === "rust-analyzer",
-        );
-    }
-
-    private setRustEditor(newRustEditor: undefined | RustEditor) {
-        if (this.rustEditor && this.rustEditor !== newRustEditor) {
-            this.rustEditor.setDecorations(this.astDecorationType, []);
-            this.rust2Ast.reset();
-        }
-        this.rustEditor = newRustEditor;
-    }
-
-    // additional positional params are omitted
-    provideDefinition(
-        doc: vscode.TextDocument,
-        pos: vscode.Position,
-    ): vscode.ProviderResult<vscode.DefinitionLink[]> {
-        if (!this.rustEditor || doc.uri.toString() !== this.rustEditor.document.uri.toString()) {
-            return;
-        }
-
-        const astEditor = this.findAstTextEditor();
-        if (!astEditor) return;
-
-        const rust2AstRanges = this.rust2Ast
-            .get()
-            ?.find(([rustRange, _]) => rustRange.contains(pos));
-        if (!rust2AstRanges) return;
-
-        const [rustFileRange, astFileRange] = rust2AstRanges;
-
-        astEditor.revealRange(astFileRange);
-        astEditor.selection = new vscode.Selection(astFileRange.start, astFileRange.end);
-
-        return [
-            {
-                targetRange: astFileRange,
-                targetUri: astEditor.document.uri,
-                originSelectionRange: rustFileRange,
-                targetSelectionRange: astFileRange,
-            },
-        ];
-    }
-
-    // additional positional params are omitted
-    provideHover(
-        doc: vscode.TextDocument,
-        hoverPosition: vscode.Position,
-    ): vscode.ProviderResult<vscode.Hover> {
-        if (!this.rustEditor) return;
-
-        const astFileLine = doc.lineAt(hoverPosition.line);
-
-        const rustFileRange = this.parseRustTextRange(this.rustEditor.document, astFileLine.text);
-        if (!rustFileRange) return;
-
-        this.rustEditor.setDecorations(this.astDecorationType, [rustFileRange]);
-        this.rustEditor.revealRange(rustFileRange);
-
-        const rustSourceCode = this.rustEditor.document.getText(rustFileRange);
-        const astFileRange = this.findAstNodeRange(astFileLine);
-
-        return new vscode.Hover(["```rust\n" + rustSourceCode + "\n```"], astFileRange);
-    }
-
-    private findAstNodeRange(astLine: vscode.TextLine): vscode.Range {
-        const lineOffset = astLine.range.start;
-        const begin = lineOffset.translate(undefined, astLine.firstNonWhitespaceCharacterIndex);
-        const end = lineOffset.translate(undefined, astLine.text.trimEnd().length);
-        return new vscode.Range(begin, end);
-    }
-
-    private parseRustTextRange(
-        doc: vscode.TextDocument,
-        astLine: string,
-    ): undefined | vscode.Range {
-        const parsedRange = /(\d+)\.\.(\d+)/.exec(astLine);
-        if (!parsedRange) return;
-
-        const [begin, end] = parsedRange.slice(1).map((off) => this.positionAt(doc, +off));
-        const actualBegin = unwrapUndefinable(begin);
-        const actualEnd = unwrapUndefinable(end);
-        return new vscode.Range(actualBegin, actualEnd);
-    }
-
-    // Memoize the last value, otherwise the CPU is at 100% single core
-    // with quadratic lookups when we build rust2Ast cache
-    cache?: { doc: vscode.TextDocument; offset: number; line: number };
-
-    positionAt(doc: vscode.TextDocument, targetOffset: number): vscode.Position {
-        if (doc.eol === vscode.EndOfLine.LF) {
-            return doc.positionAt(targetOffset);
-        }
-
-        // Dirty workaround for crlf line endings
-        // We are still in this prehistoric era of carriage returns here...
-
-        let line = 0;
-        let offset = 0;
-
-        const cache = this.cache;
-        if (cache?.doc === doc && cache.offset <= targetOffset) {
-            ({ line, offset } = cache);
-        }
-
-        while (true) {
-            const lineLenWithLf = doc.lineAt(line).text.length + 1;
-            if (offset + lineLenWithLf > targetOffset) {
-                this.cache = { doc, offset, line };
-                return doc.positionAt(targetOffset + line);
-            }
-            offset += lineLenWithLf;
-            line += 1;
-        }
-    }
-}
-
-class Lazy<T> {
-    val: undefined | T;
-
-    constructor(private readonly compute: () => undefined | T) {}
-
-    get() {
-        return this.val ?? (this.val = this.compute());
-    }
-
-    reset() {
-        this.val = undefined;
-    }
-}
diff --git a/src/tools/rust-analyzer/editors/code/src/commands.ts b/src/tools/rust-analyzer/editors/code/src/commands.ts
index 73e39c900e7..b3aa04af7ed 100644
--- a/src/tools/rust-analyzer/editors/code/src/commands.ts
+++ b/src/tools/rust-analyzer/editors/code/src/commands.ts
@@ -15,7 +15,6 @@ import {
     createTaskFromRunnable,
     createCargoArgs,
 } from "./run";
-import { AstInspector } from "./ast_inspector";
 import {
     isRustDocument,
     isCargoRunnableArgs,
@@ -31,8 +30,8 @@ import type { LanguageClient } from "vscode-languageclient/node";
 import { HOVER_REFERENCE_COMMAND } from "./client";
 import type { DependencyId } from "./dependencies_provider";
 import { log } from "./util";
+import type { SyntaxElement } from "./syntax_tree_provider";
 
-export * from "./ast_inspector";
 export * from "./run";
 
 export function analyzerStatus(ctx: CtxInit): Cmd {
@@ -288,13 +287,13 @@ export function openCargoToml(ctx: CtxInit): Cmd {
 
 export function revealDependency(ctx: CtxInit): Cmd {
     return async (editor: RustEditor) => {
-        if (!ctx.dependencies?.isInitialized()) {
+        if (!ctx.dependenciesProvider?.isInitialized()) {
             return;
         }
         const documentPath = editor.document.uri.fsPath;
-        const dep = ctx.dependencies?.getDependency(documentPath);
+        const dep = ctx.dependenciesProvider?.getDependency(documentPath);
         if (dep) {
-            await ctx.treeView?.reveal(dep, { select: true, expand: true });
+            await ctx.dependencyTreeView?.reveal(dep, { select: true, expand: true });
         } else {
             await revealParentChain(editor.document, ctx);
         }
@@ -340,10 +339,10 @@ async function revealParentChain(document: RustDocument, ctx: CtxInit) {
             // a open file referencing the old version
             return;
         }
-    } while (!ctx.dependencies?.contains(documentPath));
+    } while (!ctx.dependenciesProvider?.contains(documentPath));
     parentChain.reverse();
     for (const idx in parentChain) {
-        const treeView = ctx.treeView;
+        const treeView = ctx.dependencyTreeView;
         if (!treeView) {
             continue;
         }
@@ -357,6 +356,77 @@ export async function execRevealDependency(e: RustEditor): Promise<void> {
     await vscode.commands.executeCommand("rust-analyzer.revealDependency", e);
 }
 
+export function syntaxTreeReveal(): Cmd {
+    return async (element: SyntaxElement) => {
+        const activeEditor = vscode.window.activeTextEditor;
+
+        if (activeEditor !== undefined) {
+            const start = activeEditor.document.positionAt(element.start);
+            const end = activeEditor.document.positionAt(element.end);
+
+            const newSelection = new vscode.Selection(start, end);
+
+            activeEditor.selection = newSelection;
+            activeEditor.revealRange(newSelection);
+        }
+    };
+}
+
+function elementToString(
+    activeDocument: vscode.TextDocument,
+    element: SyntaxElement,
+    depth: number = 0,
+): string {
+    let result = "  ".repeat(depth);
+    const start = element.istart ?? element.start;
+    const end = element.iend ?? element.end;
+
+    result += `${element.kind}@${start}..${end}`;
+
+    if (element.type === "Token") {
+        const startPosition = activeDocument.positionAt(element.start);
+        const endPosition = activeDocument.positionAt(element.end);
+        const text = activeDocument.getText(new vscode.Range(startPosition, endPosition));
+        // JSON.stringify quotes and escapes the string for us.
+        result += ` ${JSON.stringify(text)}\n`;
+    } else {
+        result += "\n";
+        for (const child of element.children) {
+            result += elementToString(activeDocument, child, depth + 1);
+        }
+    }
+
+    return result;
+}
+
+export function syntaxTreeCopy(): Cmd {
+    return async (element: SyntaxElement) => {
+        const activeDocument = vscode.window.activeTextEditor?.document;
+        if (!activeDocument) {
+            return;
+        }
+
+        const result = elementToString(activeDocument, element);
+        await vscode.env.clipboard.writeText(result);
+    };
+}
+
+export function syntaxTreeHideWhitespace(ctx: CtxInit): Cmd {
+    return async () => {
+        if (ctx.syntaxTreeProvider !== undefined) {
+            await ctx.syntaxTreeProvider.toggleWhitespace();
+        }
+    };
+}
+
+export function syntaxTreeShowWhitespace(ctx: CtxInit): Cmd {
+    return async () => {
+        if (ctx.syntaxTreeProvider !== undefined) {
+            await ctx.syntaxTreeProvider.toggleWhitespace();
+        }
+    };
+}
+
 export function ssr(ctx: CtxInit): Cmd {
     return async () => {
         const editor = vscode.window.activeTextEditor;
@@ -426,89 +496,6 @@ export function serverVersion(ctx: CtxInit): Cmd {
     };
 }
 
-// Opens the virtual file that will show the syntax tree
-//
-// The contents of the file come from the `TextDocumentContentProvider`
-export function syntaxTree(ctx: CtxInit): Cmd {
-    const tdcp = new (class implements vscode.TextDocumentContentProvider {
-        readonly uri = vscode.Uri.parse("rust-analyzer-syntax-tree://syntaxtree/tree.rast");
-        readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
-        constructor() {
-            vscode.workspace.onDidChangeTextDocument(
-                this.onDidChangeTextDocument,
-                this,
-                ctx.subscriptions,
-            );
-            vscode.window.onDidChangeActiveTextEditor(
-                this.onDidChangeActiveTextEditor,
-                this,
-                ctx.subscriptions,
-            );
-        }
-
-        private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
-            if (isRustDocument(event.document)) {
-                // We need to order this after language server updates, but there's no API for that.
-                // Hence, good old sleep().
-                void sleep(10).then(() => this.eventEmitter.fire(this.uri));
-            }
-        }
-        private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
-            if (editor && isRustEditor(editor)) {
-                this.eventEmitter.fire(this.uri);
-            }
-        }
-
-        async provideTextDocumentContent(
-            uri: vscode.Uri,
-            ct: vscode.CancellationToken,
-        ): Promise<string> {
-            const rustEditor = ctx.activeRustEditor;
-            if (!rustEditor) return "";
-            const client = ctx.client;
-
-            // When the range based query is enabled we take the range of the selection
-            const range =
-                uri.query === "range=true" && !rustEditor.selection.isEmpty
-                    ? client.code2ProtocolConverter.asRange(rustEditor.selection)
-                    : null;
-
-            const params = { textDocument: { uri: rustEditor.document.uri.toString() }, range };
-            return client.sendRequest(ra.syntaxTree, params, ct);
-        }
-
-        get onDidChange(): vscode.Event<vscode.Uri> {
-            return this.eventEmitter.event;
-        }
-    })();
-
-    ctx.pushExtCleanup(new AstInspector(ctx));
-    ctx.pushExtCleanup(
-        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-syntax-tree", tdcp),
-    );
-    ctx.pushExtCleanup(
-        vscode.languages.setLanguageConfiguration("ra_syntax_tree", {
-            brackets: [["[", ")"]],
-        }),
-    );
-
-    return async () => {
-        const editor = vscode.window.activeTextEditor;
-        const rangeEnabled = !!editor && !editor.selection.isEmpty;
-
-        const uri = rangeEnabled ? vscode.Uri.parse(`${tdcp.uri.toString()}?range=true`) : tdcp.uri;
-
-        const document = await vscode.workspace.openTextDocument(uri);
-
-        tdcp.eventEmitter.fire(uri);
-
-        void (await vscode.window.showTextDocument(document, {
-            viewColumn: vscode.ViewColumn.Two,
-            preserveFocus: true,
-        }));
-    };
-}
-
 function viewHirOrMir(ctx: CtxInit, xir: "hir" | "mir"): Cmd {
     const viewXir = xir === "hir" ? "viewHir" : "viewMir";
     const requestType = xir === "hir" ? ra.viewHir : ra.viewMir;
diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts
index 720c473c5b4..d1467a4e824 100644
--- a/src/tools/rust-analyzer/editors/code/src/config.ts
+++ b/src/tools/rust-analyzer/editors/code/src/config.ts
@@ -351,6 +351,10 @@ export class Config {
         return this.get<boolean>("showDependenciesExplorer");
     }
 
+    get showSyntaxTree() {
+        return this.get<boolean>("showSyntaxTree");
+    }
+
     get statusBarClickAction() {
         return this.get<string>("statusBar.clickAction");
     }
diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts
index 37a54abf71f..5550bfa6558 100644
--- a/src/tools/rust-analyzer/editors/code/src/ctx.ts
+++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts
@@ -19,6 +19,7 @@ import {
     RustDependenciesProvider,
     type DependencyId,
 } from "./dependencies_provider";
+import { SyntaxTreeProvider, type SyntaxElement } from "./syntax_tree_provider";
 import { execRevealDependency } from "./commands";
 import { PersistentState } from "./persistent_state";
 import { bootstrap } from "./bootstrap";
@@ -84,8 +85,12 @@ export class Ctx implements RustAnalyzerExtensionApi {
     private commandFactories: Record<string, CommandFactory>;
     private commandDisposables: Disposable[];
     private unlinkedFiles: vscode.Uri[];
-    private _dependencies: RustDependenciesProvider | undefined;
-    private _treeView: vscode.TreeView<Dependency | DependencyFile | DependencyId> | undefined;
+    private _dependenciesProvider: RustDependenciesProvider | undefined;
+    private _dependencyTreeView:
+        | vscode.TreeView<Dependency | DependencyFile | DependencyId>
+        | undefined;
+    private _syntaxTreeProvider: SyntaxTreeProvider | undefined;
+    private _syntaxTreeView: vscode.TreeView<SyntaxElement> | undefined;
     private lastStatus: ServerStatusParams | { health: "stopped" } = { health: "stopped" };
     private _serverVersion: string;
     private statusBarActiveEditorListener: Disposable;
@@ -102,12 +107,20 @@ export class Ctx implements RustAnalyzerExtensionApi {
         return this._client;
     }
 
-    get treeView() {
-        return this._treeView;
+    get dependencyTreeView() {
+        return this._dependencyTreeView;
     }
 
-    get dependencies() {
-        return this._dependencies;
+    get dependenciesProvider() {
+        return this._dependenciesProvider;
+    }
+
+    get syntaxTreeView() {
+        return this._syntaxTreeView;
+    }
+
+    get syntaxTreeProvider() {
+        return this._syntaxTreeProvider;
     }
 
     constructor(
@@ -278,6 +291,9 @@ export class Ctx implements RustAnalyzerExtensionApi {
         if (this.config.showDependenciesExplorer) {
             this.prepareTreeDependenciesView(client);
         }
+        if (this.config.showSyntaxTree) {
+            this.prepareSyntaxTreeView(client);
+        }
     }
 
     private prepareTreeDependenciesView(client: lc.LanguageClient) {
@@ -285,13 +301,13 @@ export class Ctx implements RustAnalyzerExtensionApi {
             ...this,
             client: client,
         };
-        this._dependencies = new RustDependenciesProvider(ctxInit);
-        this._treeView = vscode.window.createTreeView("rustDependencies", {
-            treeDataProvider: this._dependencies,
+        this._dependenciesProvider = new RustDependenciesProvider(ctxInit);
+        this._dependencyTreeView = vscode.window.createTreeView("rustDependencies", {
+            treeDataProvider: this._dependenciesProvider,
             showCollapseAll: true,
         });
 
-        this.pushExtCleanup(this._treeView);
+        this.pushExtCleanup(this._dependencyTreeView);
         vscode.window.onDidChangeActiveTextEditor(async (e) => {
             // we should skip documents that belong to the current workspace
             if (this.shouldRevealDependency(e)) {
@@ -303,7 +319,7 @@ export class Ctx implements RustAnalyzerExtensionApi {
             }
         });
 
-        this.treeView?.onDidChangeVisibility(async (e) => {
+        this.dependencyTreeView?.onDidChangeVisibility(async (e) => {
             if (e.visible) {
                 const activeEditor = vscode.window.activeTextEditor;
                 if (this.shouldRevealDependency(activeEditor)) {
@@ -322,10 +338,60 @@ export class Ctx implements RustAnalyzerExtensionApi {
             e !== undefined &&
             isRustEditor(e) &&
             !isDocumentInWorkspace(e.document) &&
-            (this.treeView?.visible || false)
+            (this.dependencyTreeView?.visible || false)
         );
     }
 
+    private prepareSyntaxTreeView(client: lc.LanguageClient) {
+        const ctxInit: CtxInit = {
+            ...this,
+            client: client,
+        };
+        this._syntaxTreeProvider = new SyntaxTreeProvider(ctxInit);
+        this._syntaxTreeView = vscode.window.createTreeView("rustSyntaxTree", {
+            treeDataProvider: this._syntaxTreeProvider,
+            showCollapseAll: true,
+        });
+
+        this.pushExtCleanup(this._syntaxTreeView);
+
+        vscode.window.onDidChangeActiveTextEditor(async () => {
+            if (this.syntaxTreeView?.visible) {
+                await this.syntaxTreeProvider?.refresh();
+            }
+        });
+
+        vscode.workspace.onDidChangeTextDocument(async () => {
+            if (this.syntaxTreeView?.visible) {
+                await this.syntaxTreeProvider?.refresh();
+            }
+        });
+
+        vscode.window.onDidChangeTextEditorSelection(async (e) => {
+            if (!this.syntaxTreeView?.visible || !isRustEditor(e.textEditor)) {
+                return;
+            }
+
+            const selection = e.selections[0];
+            if (selection === undefined) {
+                return;
+            }
+
+            const start = e.textEditor.document.offsetAt(selection.start);
+            const end = e.textEditor.document.offsetAt(selection.end);
+            const result = this.syntaxTreeProvider?.getElementByRange(start, end);
+            if (result !== undefined) {
+                await this.syntaxTreeView?.reveal(result);
+            }
+        });
+
+        this._syntaxTreeView.onDidChangeVisibility(async (e) => {
+            if (e.visible) {
+                await this.syntaxTreeProvider?.refresh();
+            }
+        });
+    }
+
     async restart() {
         // FIXME: We should re-use the client, that is ctx.deactivate() if none of the configs have changed
         await this.stopAndDispose();
@@ -423,7 +489,8 @@ export class Ctx implements RustAnalyzerExtensionApi {
                 } else {
                     statusBar.command = "rust-analyzer.openLogs";
                 }
-                this.dependencies?.refresh();
+                this.dependenciesProvider?.refresh();
+                void this.syntaxTreeProvider?.refresh();
                 break;
             case "warning":
                 statusBar.color = new vscode.ThemeColor("statusBarItem.warningForeground");
diff --git a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
index d52e314e219..af86d9efd14 100644
--- a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
+++ b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
@@ -48,6 +48,9 @@ export const runFlycheck = new lc.NotificationType<{
 export const syntaxTree = new lc.RequestType<SyntaxTreeParams, string, void>(
     "rust-analyzer/syntaxTree",
 );
+export const viewSyntaxTree = new lc.RequestType<ViewSyntaxTreeParams, string, void>(
+    "rust-analyzer/viewSyntaxTree",
+);
 export const viewCrateGraph = new lc.RequestType<ViewCrateGraphParams, string, void>(
     "rust-analyzer/viewCrateGraph",
 );
@@ -157,6 +160,7 @@ export type SyntaxTreeParams = {
     textDocument: lc.TextDocumentIdentifier;
     range: lc.Range | null;
 };
+export type ViewSyntaxTreeParams = { textDocument: lc.TextDocumentIdentifier };
 export type ViewCrateGraphParams = { full: boolean };
 export type ViewItemTreeParams = { textDocument: lc.TextDocumentIdentifier };
 
diff --git a/src/tools/rust-analyzer/editors/code/src/main.ts b/src/tools/rust-analyzer/editors/code/src/main.ts
index fdf43f66f94..c84b69b66cd 100644
--- a/src/tools/rust-analyzer/editors/code/src/main.ts
+++ b/src/tools/rust-analyzer/editors/code/src/main.ts
@@ -158,7 +158,6 @@ function createCommands(): Record<string, CommandFactory> {
         matchingBrace: { enabled: commands.matchingBrace },
         joinLines: { enabled: commands.joinLines },
         parentModule: { enabled: commands.parentModule },
-        syntaxTree: { enabled: commands.syntaxTree },
         viewHir: { enabled: commands.viewHir },
         viewMir: { enabled: commands.viewMir },
         interpretFunction: { enabled: commands.interpretFunction },
@@ -199,6 +198,10 @@ function createCommands(): Record<string, CommandFactory> {
         rename: { enabled: commands.rename },
         openLogs: { enabled: commands.openLogs },
         revealDependency: { enabled: commands.revealDependency },
+        syntaxTreeReveal: { enabled: commands.syntaxTreeReveal },
+        syntaxTreeCopy: { enabled: commands.syntaxTreeCopy },
+        syntaxTreeHideWhitespace: { enabled: commands.syntaxTreeHideWhitespace },
+        syntaxTreeShowWhitespace: { enabled: commands.syntaxTreeShowWhitespace },
     };
 }
 
diff --git a/src/tools/rust-analyzer/editors/code/src/syntax_tree_provider.ts b/src/tools/rust-analyzer/editors/code/src/syntax_tree_provider.ts
new file mode 100644
index 00000000000..c7e8007e838
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/src/syntax_tree_provider.ts
@@ -0,0 +1,301 @@
+import * as vscode from "vscode";
+
+import { isRustEditor, setContextValue } from "./util";
+import type { CtxInit } from "./ctx";
+import * as ra from "./lsp_ext";
+
+export class SyntaxTreeProvider implements vscode.TreeDataProvider<SyntaxElement> {
+    private _onDidChangeTreeData: vscode.EventEmitter<SyntaxElement | undefined | void> =
+        new vscode.EventEmitter<SyntaxElement | undefined | void>();
+    readonly onDidChangeTreeData: vscode.Event<SyntaxElement | undefined | void> =
+        this._onDidChangeTreeData.event;
+    ctx: CtxInit;
+    root: SyntaxNode | undefined;
+    hideWhitespace: boolean = false;
+
+    constructor(ctx: CtxInit) {
+        this.ctx = ctx;
+    }
+
+    getTreeItem(element: SyntaxElement): vscode.TreeItem {
+        return new SyntaxTreeItem(element);
+    }
+
+    getChildren(element?: SyntaxElement): vscode.ProviderResult<SyntaxElement[]> {
+        return this.getRawChildren(element);
+    }
+
+    getParent(element: SyntaxElement): vscode.ProviderResult<SyntaxElement> {
+        return element.parent;
+    }
+
+    resolveTreeItem(
+        item: SyntaxTreeItem,
+        element: SyntaxElement,
+        _token: vscode.CancellationToken,
+    ): vscode.ProviderResult<SyntaxTreeItem> {
+        const editor = vscode.window.activeTextEditor;
+
+        if (editor !== undefined) {
+            const start = editor.document.positionAt(element.start);
+            const end = editor.document.positionAt(element.end);
+            const range = new vscode.Range(start, end);
+
+            const text = editor.document.getText(range);
+            item.tooltip = new vscode.MarkdownString().appendCodeblock(text, "rust");
+        }
+
+        return item;
+    }
+
+    private getRawChildren(element?: SyntaxElement): SyntaxElement[] {
+        if (element?.type === "Node") {
+            if (this.hideWhitespace) {
+                return element.children.filter((e) => e.kind !== "WHITESPACE");
+            }
+
+            return element.children;
+        }
+
+        if (element?.type === "Token") {
+            return [];
+        }
+
+        if (element === undefined && this.root !== undefined) {
+            return [this.root];
+        }
+
+        return [];
+    }
+
+    async refresh(): Promise<void> {
+        const editor = vscode.window.activeTextEditor;
+
+        if (editor && isRustEditor(editor)) {
+            const params = { textDocument: { uri: editor.document.uri.toString() }, range: null };
+            const fileText = await this.ctx.client.sendRequest(ra.viewSyntaxTree, params);
+            this.root = JSON.parse(fileText, (_key, value: SyntaxElement) => {
+                if (value.type === "Node") {
+                    for (const child of value.children) {
+                        child.parent = value;
+                    }
+                }
+
+                return value;
+            });
+        } else {
+            this.root = undefined;
+        }
+
+        this._onDidChangeTreeData.fire();
+    }
+
+    getElementByRange(start: number, end: number): SyntaxElement | undefined {
+        if (this.root === undefined) {
+            return undefined;
+        }
+
+        let result: SyntaxElement = this.root;
+
+        if (this.root.start === start && this.root.end === end) {
+            return result;
+        }
+
+        let children = this.getRawChildren(this.root);
+
+        outer: while (true) {
+            for (const child of children) {
+                if (child.start <= start && child.end >= end) {
+                    result = child;
+                    if (start === end && start === child.end) {
+                        // When the cursor is on the very end of a token,
+                        // we assume the user wants the next token instead.
+                        continue;
+                    }
+
+                    if (child.type === "Token") {
+                        return result;
+                    } else {
+                        children = this.getRawChildren(child);
+                        continue outer;
+                    }
+                }
+            }
+
+            return result;
+        }
+    }
+
+    async toggleWhitespace() {
+        this.hideWhitespace = !this.hideWhitespace;
+        this._onDidChangeTreeData.fire();
+        await setContextValue("rustSyntaxTree.hideWhitespace", this.hideWhitespace);
+    }
+}
+
+export type SyntaxNode = {
+    type: "Node";
+    kind: string;
+    start: number;
+    end: number;
+    istart?: number;
+    iend?: number;
+    children: SyntaxElement[];
+    parent?: SyntaxElement;
+};
+
+type SyntaxToken = {
+    type: "Token";
+    kind: string;
+    start: number;
+    end: number;
+    istart?: number;
+    iend?: number;
+    parent?: SyntaxElement;
+};
+
+export type SyntaxElement = SyntaxNode | SyntaxToken;
+
+export class SyntaxTreeItem extends vscode.TreeItem {
+    constructor(private readonly element: SyntaxElement) {
+        super(element.kind);
+        const icon = getIcon(element.kind);
+        if (element.type === "Node") {
+            this.contextValue = "syntaxNode";
+            this.iconPath = icon ?? new vscode.ThemeIcon("list-tree");
+            this.collapsibleState = vscode.TreeItemCollapsibleState.Expanded;
+        } else {
+            this.contextValue = "syntaxToken";
+            this.iconPath = icon ?? new vscode.ThemeIcon("symbol-string");
+            this.collapsibleState = vscode.TreeItemCollapsibleState.None;
+        }
+
+        if (element.istart !== undefined && element.iend !== undefined) {
+            this.description = `${this.element.istart}..${this.element.iend}`;
+        } else {
+            this.description = `${this.element.start}..${this.element.end}`;
+        }
+    }
+}
+
+function getIcon(kind: string): vscode.ThemeIcon | undefined {
+    const icon = iconTable[kind];
+
+    if (icon !== undefined) {
+        return icon;
+    }
+
+    if (kind.endsWith("_KW")) {
+        return new vscode.ThemeIcon(
+            "symbol-keyword",
+            new vscode.ThemeColor("symbolIcon.keywordForeground"),
+        );
+    }
+
+    if (operators.includes(kind)) {
+        return new vscode.ThemeIcon(
+            "symbol-operator",
+            new vscode.ThemeColor("symbolIcon.operatorForeground"),
+        );
+    }
+
+    return undefined;
+}
+
+const iconTable: Record<string, vscode.ThemeIcon> = {
+    CALL_EXPR: new vscode.ThemeIcon("call-outgoing"),
+    COMMENT: new vscode.ThemeIcon("comment"),
+    ENUM: new vscode.ThemeIcon("symbol-enum", new vscode.ThemeColor("symbolIcon.enumForeground")),
+    FN: new vscode.ThemeIcon(
+        "symbol-function",
+        new vscode.ThemeColor("symbolIcon.functionForeground"),
+    ),
+    FLOAT_NUMBER: new vscode.ThemeIcon(
+        "symbol-number",
+        new vscode.ThemeColor("symbolIcon.numberForeground"),
+    ),
+    INDEX_EXPR: new vscode.ThemeIcon(
+        "symbol-array",
+        new vscode.ThemeColor("symbolIcon.arrayForeground"),
+    ),
+    INT_NUMBER: new vscode.ThemeIcon(
+        "symbol-number",
+        new vscode.ThemeColor("symbolIcon.numberForeground"),
+    ),
+    LITERAL: new vscode.ThemeIcon(
+        "symbol-misc",
+        new vscode.ThemeColor("symbolIcon.miscForeground"),
+    ),
+    MODULE: new vscode.ThemeIcon(
+        "symbol-module",
+        new vscode.ThemeColor("symbolIcon.moduleForeground"),
+    ),
+    METHOD_CALL_EXPR: new vscode.ThemeIcon("call-outgoing"),
+    PARAM: new vscode.ThemeIcon(
+        "symbol-parameter",
+        new vscode.ThemeColor("symbolIcon.parameterForeground"),
+    ),
+    RECORD_FIELD: new vscode.ThemeIcon(
+        "symbol-field",
+        new vscode.ThemeColor("symbolIcon.fieldForeground"),
+    ),
+    SOURCE_FILE: new vscode.ThemeIcon("file-code"),
+    STRING: new vscode.ThemeIcon("quote"),
+    STRUCT: new vscode.ThemeIcon(
+        "symbol-struct",
+        new vscode.ThemeColor("symbolIcon.structForeground"),
+    ),
+    TRAIT: new vscode.ThemeIcon(
+        "symbol-interface",
+        new vscode.ThemeColor("symbolIcon.interfaceForeground"),
+    ),
+    TYPE_PARAM: new vscode.ThemeIcon(
+        "symbol-type-parameter",
+        new vscode.ThemeColor("symbolIcon.typeParameterForeground"),
+    ),
+    VARIANT: new vscode.ThemeIcon(
+        "symbol-enum-member",
+        new vscode.ThemeColor("symbolIcon.enumMemberForeground"),
+    ),
+    WHITESPACE: new vscode.ThemeIcon("whitespace"),
+};
+
+const operators = [
+    "PLUS",
+    "PLUSEQ",
+    "MINUS",
+    "MINUSEQ",
+    "STAR",
+    "STAREQ",
+    "SLASH",
+    "SLASHEQ",
+    "PERCENT",
+    "PERCENTEQ",
+    "CARET",
+    "CARETEQ",
+    "AMP",
+    "AMPEQ",
+    "AMP2",
+    "PIPE",
+    "PIPEEQ",
+    "PIPE2",
+    "SHL",
+    "SHLEQ",
+    "SHR",
+    "SHREQ",
+    "EQ",
+    "EQ2",
+    "BANG",
+    "NEQ",
+    "L_ANGLE",
+    "LTEQ",
+    "R_ANGLE",
+    "GTEQ",
+    "COLON2",
+    "THIN_ARROW",
+    "FAT_ARROW",
+    "DOT",
+    "DOT2",
+    "DOT2EQ",
+    "AT",
+];
diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs b/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs
index 11f98f50790..074bc43388a 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs
+++ b/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs
@@ -181,15 +181,15 @@ impl Message {
 
         Ok(Some(msg))
     }
-    pub fn write(self, w: &mut impl Write) -> io::Result<()> {
+    pub fn write(&self, w: &mut impl Write) -> io::Result<()> {
         self._write(w)
     }
-    fn _write(self, w: &mut dyn Write) -> io::Result<()> {
+    fn _write(&self, w: &mut dyn Write) -> io::Result<()> {
         #[derive(Serialize)]
-        struct JsonRpc {
+        struct JsonRpc<'a> {
             jsonrpc: &'static str,
             #[serde(flatten)]
-            msg: Message,
+            msg: &'a Message,
         }
         let text = serde_json::to_string(&JsonRpc { jsonrpc: "2.0", msg: self })?;
         write_msg_text(w, &text)
diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/socket.rs b/src/tools/rust-analyzer/lib/lsp-server/src/socket.rs
index 36d728456f7..48400abf229 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/src/socket.rs
+++ b/src/tools/rust-analyzer/lib/lsp-server/src/socket.rs
@@ -15,8 +15,11 @@ pub(crate) fn socket_transport(
     stream: TcpStream,
 ) -> (Sender<Message>, Receiver<Message>, IoThreads) {
     let (reader_receiver, reader) = make_reader(stream.try_clone().unwrap());
-    let (writer_sender, writer) = make_write(stream);
-    let io_threads = make_io_threads(reader, writer);
+    let (writer_sender, writer, messages_to_drop) = make_write(stream);
+    let dropper = std::thread::spawn(move || {
+        messages_to_drop.into_iter().for_each(drop);
+    });
+    let io_threads = make_io_threads(reader, writer, dropper);
     (writer_sender, reader_receiver, io_threads)
 }
 
@@ -36,11 +39,21 @@ fn make_reader(stream: TcpStream) -> (Receiver<Message>, thread::JoinHandle<io::
     (reader_receiver, reader)
 }
 
-fn make_write(mut stream: TcpStream) -> (Sender<Message>, thread::JoinHandle<io::Result<()>>) {
+fn make_write(
+    mut stream: TcpStream,
+) -> (Sender<Message>, thread::JoinHandle<io::Result<()>>, Receiver<Message>) {
     let (writer_sender, writer_receiver) = bounded::<Message>(0);
+    let (drop_sender, drop_receiver) = bounded::<Message>(0);
     let writer = thread::spawn(move || {
-        writer_receiver.into_iter().try_for_each(|it| it.write(&mut stream)).unwrap();
+        writer_receiver
+            .into_iter()
+            .try_for_each(|it| {
+                let result = it.write(&mut stream);
+                let _ = drop_sender.send(it);
+                result
+            })
+            .unwrap();
         Ok(())
     });
-    (writer_sender, writer)
+    (writer_sender, writer, drop_receiver)
 }
diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/stdio.rs b/src/tools/rust-analyzer/lib/lsp-server/src/stdio.rs
index 279a6bce080..8344c9f56b5 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/src/stdio.rs
+++ b/src/tools/rust-analyzer/lib/lsp-server/src/stdio.rs
@@ -11,15 +11,24 @@ use crate::Message;
 
 /// Creates an LSP connection via stdio.
 pub(crate) fn stdio_transport() -> (Sender<Message>, Receiver<Message>, IoThreads) {
+    let (drop_sender, drop_receiver) = bounded::<Message>(0);
     let (writer_sender, writer_receiver) = bounded::<Message>(0);
     let writer = thread::Builder::new()
         .name("LspServerWriter".to_owned())
         .spawn(move || {
             let stdout = stdout();
             let mut stdout = stdout.lock();
-            writer_receiver.into_iter().try_for_each(|it| it.write(&mut stdout))
+            writer_receiver.into_iter().try_for_each(|it| {
+                let result = it.write(&mut stdout);
+                let _ = drop_sender.send(it);
+                result
+            })
         })
         .unwrap();
+    let dropper = thread::Builder::new()
+        .name("LspMessageDropper".to_owned())
+        .spawn(move || drop_receiver.into_iter().for_each(drop))
+        .unwrap();
     let (reader_sender, reader_receiver) = bounded::<Message>(0);
     let reader = thread::Builder::new()
         .name("LspServerReader".to_owned())
@@ -41,7 +50,7 @@ pub(crate) fn stdio_transport() -> (Sender<Message>, Receiver<Message>, IoThread
             Ok(())
         })
         .unwrap();
-    let threads = IoThreads { reader, writer };
+    let threads = IoThreads { reader, writer, dropper };
     (writer_sender, reader_receiver, threads)
 }
 
@@ -49,13 +58,15 @@ pub(crate) fn stdio_transport() -> (Sender<Message>, Receiver<Message>, IoThread
 pub(crate) fn make_io_threads(
     reader: thread::JoinHandle<io::Result<()>>,
     writer: thread::JoinHandle<io::Result<()>>,
+    dropper: thread::JoinHandle<()>,
 ) -> IoThreads {
-    IoThreads { reader, writer }
+    IoThreads { reader, writer, dropper }
 }
 
 pub struct IoThreads {
     reader: thread::JoinHandle<io::Result<()>>,
     writer: thread::JoinHandle<io::Result<()>>,
+    dropper: thread::JoinHandle<()>,
 }
 
 impl IoThreads {
@@ -64,6 +75,12 @@ impl IoThreads {
             Ok(r) => r?,
             Err(err) => std::panic::panic_any(err),
         }
+        match self.dropper.join() {
+            Ok(_) => (),
+            Err(err) => {
+                std::panic::panic_any(err);
+            }
+        }
         match self.writer.join() {
             Ok(r) => r,
             Err(err) => {
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index 517fdfe18ed..2d9a927c638 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-fb546ee09b226bc4dd4b712d35a372d923c4fa54
+9a1d156f38c51441ee51e5a068f1d0caf4bb0f27
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index e05b3c33ca3..86d2abcacb7 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -86,11 +86,12 @@ dependencies = [
 
 [[package]]
 name = "anstyle-wincon"
-version = "3.0.6"
+version = "3.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
+checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
 dependencies = [
  "anstyle",
+ "once_cell",
  "windows-sys",
 ]
 
@@ -123,9 +124,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bitflags"
-version = "2.7.0"
+version = "2.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be"
+checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
 
 [[package]]
 name = "block-buffer"
@@ -161,9 +162,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "cc"
-version = "1.2.8"
+version = "1.2.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad0cf6e91fde44c773c6ee7ec6bba798504641a8bc2eb7e37a04ffbf4dfaa55a"
+checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229"
 dependencies = [
  "shlex",
 ]
@@ -771,9 +772,9 @@ checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
 
 [[package]]
 name = "js-sys"
-version = "0.3.76"
+version = "0.3.77"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7"
+checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
 dependencies = [
  "once_cell",
  "wasm-bindgen",
@@ -834,9 +835,9 @@ dependencies = [
 
 [[package]]
 name = "log"
-version = "0.4.22"
+version = "0.4.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
 
 [[package]]
 name = "mac"
@@ -951,9 +952,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.8.2"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394"
+checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924"
 dependencies = [
  "adler2",
 ]
@@ -1219,7 +1220,7 @@ version = "0.10.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993"
 dependencies = [
- "bitflags 2.7.0",
+ "bitflags 2.8.0",
  "memchr",
  "pulldown-cmark-escape 0.10.1",
  "unicase",
@@ -1231,7 +1232,7 @@ version = "0.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625"
 dependencies = [
- "bitflags 2.7.0",
+ "bitflags 2.8.0",
  "memchr",
  "pulldown-cmark-escape 0.11.0",
  "unicase",
@@ -1243,7 +1244,7 @@ version = "0.12.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14"
 dependencies = [
- "bitflags 2.7.0",
+ "bitflags 2.8.0",
  "getopts",
  "memchr",
  "pulldown-cmark-escape 0.11.0",
@@ -1325,7 +1326,7 @@ version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
 dependencies = [
- "bitflags 2.7.0",
+ "bitflags 2.8.0",
 ]
 
 [[package]]
@@ -1375,7 +1376,7 @@ version = "0.38.43"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6"
 dependencies = [
- "bitflags 2.7.0",
+ "bitflags 2.8.0",
  "errno",
  "libc",
  "linux-raw-sys",
@@ -1383,6 +1384,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "rustversion"
+version = "1.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
+
+[[package]]
 name = "ryu"
 version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1794,20 +1801,21 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.99"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396"
+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
 dependencies = [
  "cfg-if",
  "once_cell",
+ "rustversion",
  "wasm-bindgen-macro",
 ]
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.99"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79"
+checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
 dependencies = [
  "bumpalo",
  "log",
@@ -1819,9 +1827,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.99"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe"
+checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -1829,9 +1837,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.99"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
+checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1842,9 +1850,12 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.99"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
+checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+dependencies = [
+ "unicode-ident",
+]
 
 [[package]]
 name = "winapi"
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 575716eb6dd..6f0fd09b353 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -1,5 +1,3 @@
-run-make/cat-and-grep-sanity-check/Makefile
-run-make/jobserver-error/Makefile
 run-make/split-debuginfo/Makefile
 run-make/symbol-mangling-hashed/Makefile
 run-make/translation/Makefile
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index d4cbc37f6d2..59e0042e5c9 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -438,6 +438,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "windows-implement",
     "windows-interface",
     "windows-result",
+    "windows-strings",
     "windows-sys",
     "windows-targets",
     "windows_aarch64_gnullvm",
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index 54de2ef8314..de3380502bf 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -183,7 +183,6 @@ ui/async-await/issue-67252-unnamed-future.rs
 ui/async-await/issue-67651.rs
 ui/async-await/issue-67765-async-diagnostic.rs
 ui/async-await/issue-68112.rs
-ui/async-await/issue-68523-start.rs
 ui/async-await/issue-68523.rs
 ui/async-await/issue-69446-fnmut-capture.rs
 ui/async-await/issue-70594.rs
@@ -2395,7 +2394,6 @@ ui/issues/issue-50618.rs
 ui/issues/issue-5062.rs
 ui/issues/issue-5067.rs
 ui/issues/issue-50688.rs
-ui/issues/issue-50714-1.rs
 ui/issues/issue-50714.rs
 ui/issues/issue-50761.rs
 ui/issues/issue-50781.rs
@@ -2630,7 +2628,6 @@ ui/issues/issue-9259.rs
 ui/issues/issue-92741.rs
 ui/issues/issue-9382.rs
 ui/issues/issue-9446.rs
-ui/issues/issue-9575.rs
 ui/issues/issue-9719.rs
 ui/issues/issue-9725.rs
 ui/issues/issue-9737.rs
@@ -2645,7 +2642,6 @@ ui/issues/issue-9968.rs
 ui/issues/issue-99838.rs
 ui/iterators/issue-28098.rs
 ui/iterators/issue-58952-filter-type-length.rs
-ui/lang-items/issue-19660.rs
 ui/lang-items/issue-83471.rs
 ui/lang-items/issue-87573.rs
 ui/late-bound-lifetimes/issue-36381.rs
@@ -3702,7 +3698,6 @@ ui/rfcs/rfc-2005-default-binding-mode/issue-44912-or.rs
 ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs
 ui/rfcs/rfc-2093-infer-outlives/issue-54467.rs
 ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-main.rs
-ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.rs
 ui/rfcs/rfc-2396-target_feature-11/issue-108655-inline-always-closure.rs
 ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs
 ui/rfcs/rfc-2497-if-let-chains/issue-88498.rs
diff --git a/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs b/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs
index 00edf99a30d..ee92d302db3 100644
--- a/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs
+++ b/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs
@@ -58,7 +58,7 @@ pub fn check(tests_path: impl AsRef<Path>, bad: &mut bool) {
 
             let mut expected_revisions = BTreeSet::new();
 
-            let contents = std::fs::read_to_string(test).unwrap();
+            let Ok(contents) = std::fs::read_to_string(test) else { continue };
 
             // Collect directives.
             iter_header(&contents, &mut |HeaderLine { revision, directive, .. }| {
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 401169c838f..63ac447a772 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -17,7 +17,7 @@ use ignore::Walk;
 const ENTRY_LIMIT: u32 = 901;
 // FIXME: The following limits should be reduced eventually.
 
-const ISSUES_ENTRY_LIMIT: u32 = 1667;
+const ISSUES_ENTRY_LIMIT: u32 = 1664;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
     "rs",     // test source files
diff --git a/src/tools/wasm-component-ld/Cargo.toml b/src/tools/wasm-component-ld/Cargo.toml
index 965e9b01a44..f8ae91f9e6f 100644
--- a/src/tools/wasm-component-ld/Cargo.toml
+++ b/src/tools/wasm-component-ld/Cargo.toml
@@ -10,4 +10,4 @@ name = "wasm-component-ld"
 path = "src/main.rs"
 
 [dependencies]
-wasm-component-ld = "0.5.11"
+wasm-component-ld = "0.5.12"
diff --git a/tests/codegen-units/item-collection/cross-crate-closures.rs b/tests/codegen-units/item-collection/cross-crate-closures.rs
index cb86cf18c0c..75a77cc2671 100644
--- a/tests/codegen-units/item-collection/cross-crate-closures.rs
+++ b/tests/codegen-units/item-collection/cross-crate-closures.rs
@@ -3,14 +3,14 @@
 //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
 
 #![deny(dead_code)]
-#![feature(start)]
+#![no_main]
 
 //@ aux-build:cgu_extern_closures.rs
 extern crate cgu_extern_closures;
 
-//~ MONO_ITEM fn start @@ cross_crate_closures-cgu.0[Internal]
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+//~ MONO_ITEM fn main @@ cross_crate_closures-cgu.0[External]
+#[no_mangle]
+extern "C" fn main(_: core::ffi::c_int, _: *const *const u8) -> core::ffi::c_int {
     //~ MONO_ITEM fn cgu_extern_closures::inlined_fn @@ cross_crate_closures-cgu.0[Internal]
     //~ MONO_ITEM fn cgu_extern_closures::inlined_fn::{closure#0} @@ cross_crate_closures-cgu.0[Internal]
     let _ = cgu_extern_closures::inlined_fn(1, 2);
diff --git a/tests/codegen-units/item-collection/cross-crate-generic-functions.rs b/tests/codegen-units/item-collection/cross-crate-generic-functions.rs
index d36f7067b32..4382bfdf8d8 100644
--- a/tests/codegen-units/item-collection/cross-crate-generic-functions.rs
+++ b/tests/codegen-units/item-collection/cross-crate-generic-functions.rs
@@ -1,14 +1,14 @@
 //@ compile-flags:-Zprint-mono-items=eager
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 //@ aux-build:cgu_generic_function.rs
 extern crate cgu_generic_function;
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn cgu_generic_function::bar::<u32>
     //~ MONO_ITEM fn cgu_generic_function::foo::<u32>
     let _ = cgu_generic_function::foo(1u32);
diff --git a/tests/codegen-units/item-collection/cross-crate-trait-method.rs b/tests/codegen-units/item-collection/cross-crate-trait-method.rs
index 99777760315..917354166f5 100644
--- a/tests/codegen-units/item-collection/cross-crate-trait-method.rs
+++ b/tests/codegen-units/item-collection/cross-crate-trait-method.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no -Copt-level=0
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 //@ aux-build:cgu_export_trait_method.rs
 extern crate cgu_export_trait_method;
@@ -9,8 +9,8 @@ extern crate cgu_export_trait_method;
 use cgu_export_trait_method::Trait;
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     // The object code of these methods is contained in the external crate, so
     // calling them should *not* introduce codegen items in the current crate.
     let _: (u32, u32) = Trait::without_default_impl(0);
diff --git a/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs b/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs
index d87ad41e70d..e1887b93b93 100644
--- a/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs
+++ b/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs
@@ -3,7 +3,7 @@
 //@ compile-flags:-Zinline-in-all-cgus
 //@ compile-flags:-Zinline-mir=no
 
-#![feature(start)]
+#![crate_type = "lib"]
 
 //~ MONO_ITEM fn std::ptr::drop_in_place::<StructWithDtor> - shim(Some(StructWithDtor)) @@ drop_in_place_intrinsic-cgu.0[Internal]
 struct StructWithDtor(u32);
@@ -14,8 +14,8 @@ impl Drop for StructWithDtor {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn std::ptr::drop_in_place::<[StructWithDtor; 2]> - shim(Some([StructWithDtor; 2])) @@ drop_in_place_intrinsic-cgu.0[Internal]
     let x = [StructWithDtor(0), StructWithDtor(1)];
 
diff --git a/tests/codegen-units/item-collection/function-as-argument.rs b/tests/codegen-units/item-collection/function-as-argument.rs
index 4be713dc367..146a53bb911 100644
--- a/tests/codegen-units/item-collection/function-as-argument.rs
+++ b/tests/codegen-units/item-collection/function-as-argument.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 fn take_fn_once<T1, T2, F: FnOnce(T1, T2)>(f: F, x: T1, y: T2) {
     (f)(x, y)
@@ -14,8 +14,8 @@ fn take_fn_pointer<T1, T2>(f: fn(T1, T2), x: T1, y: T2) {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn take_fn_once::<u32, &str, fn(u32, &str) {function::<u32, &str>}>
     //~ MONO_ITEM fn function::<u32, &str>
     //~ MONO_ITEM fn <fn(u32, &str) {function::<u32, &str>} as std::ops::FnOnce<(u32, &str)>>::call_once - shim(fn(u32, &str) {function::<u32, &str>})
diff --git a/tests/codegen-units/item-collection/generic-drop-glue.rs b/tests/codegen-units/item-collection/generic-drop-glue.rs
index d861d269fae..6ecf98a032f 100644
--- a/tests/codegen-units/item-collection/generic-drop-glue.rs
+++ b/tests/codegen-units/item-collection/generic-drop-glue.rs
@@ -3,7 +3,7 @@
 //@ compile-flags:-Zinline-in-all-cgus
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 struct StructWithDrop<T1, T2> {
     x: T1,
@@ -44,8 +44,8 @@ impl Drop for NonGenericWithDrop {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn std::ptr::drop_in_place::<StructWithDrop<i8, char>> - shim(Some(StructWithDrop<i8, char>)) @@ generic_drop_glue-cgu.0[Internal]
     //~ MONO_ITEM fn <StructWithDrop<i8, char> as std::ops::Drop>::drop
     let _ = StructWithDrop { x: 0i8, y: 'a' }.x;
diff --git a/tests/codegen-units/item-collection/generic-functions.rs b/tests/codegen-units/item-collection/generic-functions.rs
index 2d7c70c9c4c..4a890790702 100644
--- a/tests/codegen-units/item-collection/generic-functions.rs
+++ b/tests/codegen-units/item-collection/generic-functions.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 fn foo1<T1>(a: T1) -> (T1, u32) {
     (a, 1)
@@ -22,8 +22,8 @@ pub fn lifetime_only<'a>(a: &'a u32) -> &'a u32 {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn foo1::<i32>
     let _ = foo1(2i32);
     //~ MONO_ITEM fn foo1::<i64>
diff --git a/tests/codegen-units/item-collection/generic-impl.rs b/tests/codegen-units/item-collection/generic-impl.rs
index f6e49f6e6df..5a43bd64b2a 100644
--- a/tests/codegen-units/item-collection/generic-impl.rs
+++ b/tests/codegen-units/item-collection/generic-impl.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 struct Struct<T> {
     x: T,
@@ -38,8 +38,8 @@ impl<'a> LifeTimeOnly<'a> {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn Struct::<i32>::new
     //~ MONO_ITEM fn id::<i32>
     //~ MONO_ITEM fn Struct::<i32>::get::<i16>
diff --git a/tests/codegen-units/item-collection/impl-in-non-instantiated-generic.rs b/tests/codegen-units/item-collection/impl-in-non-instantiated-generic.rs
index 0b7f30187b5..d916fa6a825 100644
--- a/tests/codegen-units/item-collection/impl-in-non-instantiated-generic.rs
+++ b/tests/codegen-units/item-collection/impl-in-non-instantiated-generic.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 trait SomeTrait {
     fn foo(&self);
@@ -19,8 +19,8 @@ pub fn generic_function<T>(x: T) -> (T, i32) {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     0i64.foo();
 
     0
diff --git a/tests/codegen-units/item-collection/instantiation-through-vtable.rs b/tests/codegen-units/item-collection/instantiation-through-vtable.rs
index 59dd4311a03..9087fc6410a 100644
--- a/tests/codegen-units/item-collection/instantiation-through-vtable.rs
+++ b/tests/codegen-units/item-collection/instantiation-through-vtable.rs
@@ -2,7 +2,7 @@
 //@ compile-flags:-Zprint-mono-items=eager -Zinline-in-all-cgus -Zmir-opt-level=0
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 trait Trait {
     fn foo(&self) -> u32;
@@ -21,8 +21,8 @@ impl<T> Trait for Struct<T> {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     let s1 = Struct { _a: 0u32 };
 
     //~ MONO_ITEM fn std::ptr::drop_in_place::<Struct<u32>> - shim(None) @@ instantiation_through_vtable-cgu.0[Internal]
diff --git a/tests/codegen-units/item-collection/items-within-generic-items.rs b/tests/codegen-units/item-collection/items-within-generic-items.rs
index 7798d2b46d2..56d21d5895c 100644
--- a/tests/codegen-units/item-collection/items-within-generic-items.rs
+++ b/tests/codegen-units/item-collection/items-within-generic-items.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager -Copt-level=0
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 fn generic_fn<T>(a: T) -> (T, i32) {
     //~ MONO_ITEM fn generic_fn::nested_fn
@@ -22,8 +22,8 @@ fn generic_fn<T>(a: T) -> (T, i32) {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn generic_fn::<i64>
     let _ = generic_fn(0i64);
     //~ MONO_ITEM fn generic_fn::<u16>
diff --git a/tests/codegen-units/item-collection/non-generic-closures.rs b/tests/codegen-units/item-collection/non-generic-closures.rs
index 8847a249b1e..4dbc0b62b97 100644
--- a/tests/codegen-units/item-collection/non-generic-closures.rs
+++ b/tests/codegen-units/item-collection/non-generic-closures.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 //~ MONO_ITEM fn temporary @@ non_generic_closures-cgu.0[Internal]
 fn temporary() {
@@ -40,9 +40,9 @@ fn assigned_to_variable_executed_directly() {
     f(4);
 }
 
-//~ MONO_ITEM fn start @@ non_generic_closures-cgu.0[Internal]
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+//~ MONO_ITEM fn start @@ non_generic_closures-cgu.0[External]
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     temporary();
     assigned_to_variable_but_not_executed();
     assigned_to_variable_executed_directly();
diff --git a/tests/codegen-units/item-collection/non-generic-drop-glue.rs b/tests/codegen-units/item-collection/non-generic-drop-glue.rs
index f7bb2f3f2f4..c4d7942ba1e 100644
--- a/tests/codegen-units/item-collection/non-generic-drop-glue.rs
+++ b/tests/codegen-units/item-collection/non-generic-drop-glue.rs
@@ -3,7 +3,7 @@
 //@ compile-flags:-Zinline-in-all-cgus
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 //~ MONO_ITEM fn std::ptr::drop_in_place::<StructWithDrop> - shim(Some(StructWithDrop)) @@ non_generic_drop_glue-cgu.0[Internal]
 struct StructWithDrop {
@@ -34,8 +34,8 @@ enum EnumNoDrop {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     let _ = StructWithDrop { x: 0 }.x;
     let _ = StructNoDrop { x: 0 }.x;
     let _ = match EnumWithDrop::A(0) {
diff --git a/tests/codegen-units/item-collection/non-generic-functions.rs b/tests/codegen-units/item-collection/non-generic-functions.rs
index d4d7d221827..4b86b1088f1 100644
--- a/tests/codegen-units/item-collection/non-generic-functions.rs
+++ b/tests/codegen-units/item-collection/non-generic-functions.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 //~ MONO_ITEM fn foo
 fn foo() {
@@ -62,8 +62,8 @@ impl Struct {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     foo();
     bar();
     Struct::foo();
diff --git a/tests/codegen-units/item-collection/static-init.rs b/tests/codegen-units/item-collection/static-init.rs
index 44b80ef73a4..5e3d06790a2 100644
--- a/tests/codegen-units/item-collection/static-init.rs
+++ b/tests/codegen-units/item-collection/static-init.rs
@@ -1,16 +1,16 @@
 //@ compile-flags:-Zprint-mono-items=eager
 
-#![feature(start)]
+#![crate_type = "lib"]
 
-pub static FN: fn() = foo::<i32>;
+static FN: fn() = foo::<i32>;
 
-pub fn foo<T>() {}
+fn foo<T>() {}
 
 //~ MONO_ITEM fn foo::<i32>
 //~ MONO_ITEM static FN
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     0
 }
diff --git a/tests/codegen-units/item-collection/statics-and-consts.rs b/tests/codegen-units/item-collection/statics-and-consts.rs
index 1e3782f0c6e..54297a40851 100644
--- a/tests/codegen-units/item-collection/statics-and-consts.rs
+++ b/tests/codegen-units/item-collection/statics-and-consts.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 static STATIC1: i64 = {
     const STATIC1_CONST1: i64 = 2;
@@ -38,8 +38,8 @@ fn foo() {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     foo();
     let _ = STATIC1;
 
diff --git a/tests/codegen-units/item-collection/trait-implementations.rs b/tests/codegen-units/item-collection/trait-implementations.rs
index e4c444499e0..3b67d4f22bd 100644
--- a/tests/codegen-units/item-collection/trait-implementations.rs
+++ b/tests/codegen-units/item-collection/trait-implementations.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 pub trait SomeTrait {
     fn foo(&self);
@@ -42,8 +42,8 @@ impl<T> SomeGenericTrait<T> for f32 {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn <i32 as SomeTrait>::bar::<char>
     0i32.bar('x');
 
diff --git a/tests/codegen-units/item-collection/trait-method-as-argument.rs b/tests/codegen-units/item-collection/trait-method-as-argument.rs
index 10cf2a0e967..d425ea19988 100644
--- a/tests/codegen-units/item-collection/trait-method-as-argument.rs
+++ b/tests/codegen-units/item-collection/trait-method-as-argument.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 trait Trait: Sized {
     fn foo(self) -> Self {
@@ -30,8 +30,8 @@ fn take_foo_mut<T, F: FnMut(T) -> T>(mut f: F, arg: T) -> T {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn take_foo_once::<u32, fn(u32) -> u32 {<u32 as Trait>::foo}>
     //~ MONO_ITEM fn <u32 as Trait>::foo
     //~ MONO_ITEM fn <fn(u32) -> u32 {<u32 as Trait>::foo} as std::ops::FnOnce<(u32,)>>::call_once - shim(fn(u32) -> u32 {<u32 as Trait>::foo})
diff --git a/tests/codegen-units/item-collection/trait-method-default-impl.rs b/tests/codegen-units/item-collection/trait-method-default-impl.rs
index fd73786a402..cd0a4b89031 100644
--- a/tests/codegen-units/item-collection/trait-method-default-impl.rs
+++ b/tests/codegen-units/item-collection/trait-method-default-impl.rs
@@ -1,7 +1,7 @@
 //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 trait SomeTrait {
     fn foo(&self) {}
@@ -39,8 +39,8 @@ impl<T1> SomeGenericTrait<T1> for u32 {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn <i8 as SomeTrait>::bar::<char>
     let _ = 1i8.bar('c');
 
diff --git a/tests/codegen-units/item-collection/transitive-drop-glue.rs b/tests/codegen-units/item-collection/transitive-drop-glue.rs
index 7c879dee1a1..18954fab86f 100644
--- a/tests/codegen-units/item-collection/transitive-drop-glue.rs
+++ b/tests/codegen-units/item-collection/transitive-drop-glue.rs
@@ -3,7 +3,7 @@
 //@ compile-flags:-Zinline-in-all-cgus
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 //~ MONO_ITEM fn std::ptr::drop_in_place::<Root> - shim(Some(Root)) @@ transitive_drop_glue-cgu.0[Internal]
 struct Root(#[allow(dead_code)] Intermediate);
@@ -26,8 +26,8 @@ impl<T> Drop for LeafGen<T> {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     let _ = Root(Intermediate(Leaf));
 
     //~ MONO_ITEM fn std::ptr::drop_in_place::<RootGen<u32>> - shim(Some(RootGen<u32>)) @@ transitive_drop_glue-cgu.0[Internal]
diff --git a/tests/codegen-units/item-collection/tuple-drop-glue.rs b/tests/codegen-units/item-collection/tuple-drop-glue.rs
index 9d8b0cdd384..2e70d0151eb 100644
--- a/tests/codegen-units/item-collection/tuple-drop-glue.rs
+++ b/tests/codegen-units/item-collection/tuple-drop-glue.rs
@@ -3,7 +3,7 @@
 //@ compile-flags:-Zinline-in-all-cgus
 
 #![deny(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 //~ MONO_ITEM fn std::ptr::drop_in_place::<Dropped> - shim(Some(Dropped)) @@ tuple_drop_glue-cgu.0[Internal]
 struct Dropped;
@@ -14,8 +14,8 @@ impl Drop for Dropped {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     //~ MONO_ITEM fn std::ptr::drop_in_place::<(u32, Dropped)> - shim(Some((u32, Dropped))) @@ tuple_drop_glue-cgu.0[Internal]
     let x = (0u32, Dropped);
 
diff --git a/tests/codegen-units/item-collection/unsizing.rs b/tests/codegen-units/item-collection/unsizing.rs
index 5ea8b47962a..23e6003dc19 100644
--- a/tests/codegen-units/item-collection/unsizing.rs
+++ b/tests/codegen-units/item-collection/unsizing.rs
@@ -5,7 +5,7 @@
 #![deny(dead_code)]
 #![feature(coerce_unsized)]
 #![feature(unsize)]
-#![feature(start)]
+#![crate_type = "lib"]
 
 use std::marker::Unsize;
 use std::ops::CoerceUnsized;
@@ -45,8 +45,8 @@ struct Wrapper<T: ?Sized>(#[allow(dead_code)] *const T);
 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Wrapper<U>> for Wrapper<T> {}
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
     // simple case
     let bool_sized = &true;
     //~ MONO_ITEM fn std::ptr::drop_in_place::<bool> - shim(None) @@ unsizing-cgu.0[Internal]
diff --git a/tests/codegen-units/partitioning/methods-are-with-self-type.rs b/tests/codegen-units/partitioning/methods-are-with-self-type.rs
index 7c9045e8f1a..94d06829c6c 100644
--- a/tests/codegen-units/partitioning/methods-are-with-self-type.rs
+++ b/tests/codegen-units/partitioning/methods-are-with-self-type.rs
@@ -46,6 +46,7 @@ mod type2 {
 }
 
 //~ MONO_ITEM fn start @@ methods_are_with_self_type[External]
+#[no_mangle]
 pub fn start() {
     //~ MONO_ITEM fn mod1::<impl SomeGenericType<u32, u64>>::method @@ methods_are_with_self_type.volatile[External]
     SomeGenericType(0u32, 0u64).method();
diff --git a/tests/codegen-units/partitioning/vtable-through-const.rs b/tests/codegen-units/partitioning/vtable-through-const.rs
index a9186cea9c8..3880bba6f6b 100644
--- a/tests/codegen-units/partitioning/vtable-through-const.rs
+++ b/tests/codegen-units/partitioning/vtable-through-const.rs
@@ -2,11 +2,13 @@
 //@ incremental
 //@ compile-flags:-Zprint-mono-items=lazy
 //@ compile-flags:-Zinline-in-all-cgus
+// Need to disable optimizations to ensure consistent output across all CI runners.
+//@ compile-flags:-Copt-level=0
 
 // This test case makes sure, that references made through constants are
 // recorded properly in the InliningMap.
 
-#![feature(start)]
+#![crate_type = "lib"]
 
 mod mod1 {
     struct NeedsDrop;
@@ -51,8 +53,8 @@ mod mod1 {
         fn do_something_else(&self) {}
     }
 
-    //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2>::do_something @@ vtable_through_const-mod1.volatile[Internal]
-    //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2>::do_something_else @@ vtable_through_const-mod1.volatile[Internal]
+    //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2>::do_something @@ vtable_through_const-mod1.volatile[External]
+    //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2>::do_something_else @@ vtable_through_const-mod1.volatile[External]
     impl Trait2 for NeedsDrop {}
 
     pub trait Trait2Gen<T> {
@@ -76,9 +78,9 @@ mod mod1 {
 }
 
 //~ MONO_ITEM fn start
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
-    //~ MONO_ITEM fn <mod1::NeedsDrop as std::ops::Drop>::drop @@ vtable_through_const-fallback.cgu[Internal]
+#[no_mangle]
+pub fn start(_: isize, _: *const *const u8) -> isize {
+    //~ MONO_ITEM fn <mod1::NeedsDrop as std::ops::Drop>::drop @@ vtable_through_const-fallback.cgu[External]
     //~ MONO_ITEM fn std::ptr::drop_in_place::<mod1::NeedsDrop> - shim(Some(mod1::NeedsDrop)) @@ vtable_through_const-fallback.cgu[External]
 
     // Since Trait1::do_something() is instantiated via its default implementation,
@@ -95,8 +97,8 @@ fn start(_: isize, _: *const *const u8) -> isize {
     // Same as above
     //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait1Gen<u8>>::do_something @@ vtable_through_const-mod1.volatile[External]
     //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait1Gen<u8>>::do_something_else @@ vtable_through_const-mod1.volatile[External]
-    //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2Gen<u8>>::do_something @@ vtable_through_const-mod1.volatile[Internal]
-    //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2Gen<u8>>::do_something_else @@ vtable_through_const-mod1.volatile[Internal]
+    //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2Gen<u8>>::do_something @@ vtable_through_const-mod1.volatile[External]
+    //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2Gen<u8>>::do_something_else @@ vtable_through_const-mod1.volatile[External]
     mod1::TRAIT1_GEN_REF.do_something(0u8);
 
     //~ MONO_ITEM fn mod1::id::<char> @@ vtable_through_const-mod1.volatile[External]
diff --git a/tests/codegen/gdb_debug_script_load.rs b/tests/codegen/gdb_debug_script_load.rs
index 30d518c0bcb..3e92eba10b1 100644
--- a/tests/codegen/gdb_debug_script_load.rs
+++ b/tests/codegen/gdb_debug_script_load.rs
@@ -4,14 +4,34 @@
 //@ ignore-wasm
 //@ ignore-emscripten
 
-//@ compile-flags: -g -C no-prepopulate-passes
+//@ compile-flags: -g -C no-prepopulate-passes -Cpanic=abort
 
-#![feature(start)]
+#![feature(lang_items)]
+#![no_std]
 
+#[panic_handler]
+fn panic_handler(_: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
+
+#[no_mangle]
+extern "C" fn rust_eh_personality() {
+    loop {}
+}
+
+// Needs rustc to generate `main` as that's where the magic load is inserted.
+// IOW, we cannot write this test with `#![no_main]`.
 // CHECK-LABEL: @main
 // CHECK: load volatile i8, {{.+}} @__rustc_debug_gdb_scripts_section__
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[lang = "start"]
+fn lang_start<T: 'static>(
+    _main: fn() -> T,
+    _argc: isize,
+    _argv: *const *const u8,
+    _sigpipe: u8,
+) -> isize {
     return 0;
 }
+
+fn main() {}
diff --git a/tests/codegen/hint/cold_path.rs b/tests/codegen/hint/cold_path.rs
new file mode 100644
index 00000000000..dac72073f85
--- /dev/null
+++ b/tests/codegen/hint/cold_path.rs
@@ -0,0 +1,54 @@
+//@ compile-flags: -O
+#![crate_type = "lib"]
+#![feature(cold_path)]
+
+use std::hint::cold_path;
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_a() {
+    println!("path a");
+}
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_b() {
+    println!("path b");
+}
+
+#[no_mangle]
+pub fn test1(x: bool) {
+    if x {
+        path_a();
+    } else {
+        cold_path();
+        path_b();
+    }
+
+    // CHECK-LABEL: @test1(
+    // CHECK: br i1 %x, label %bb1, label %bb2, !prof ![[NUM:[0-9]+]]
+    // CHECK: bb2:
+    // CHECK: path_b
+    // CHECK: bb1:
+    // CHECK: path_a
+}
+
+#[no_mangle]
+pub fn test2(x: i32) {
+    match x > 0 {
+        true => path_a(),
+        false => {
+            cold_path();
+            path_b()
+        }
+    }
+
+    // CHECK-LABEL: @test2(
+    // CHECK: br i1 %_2, label %bb2, label %bb1, !prof ![[NUM]]
+    // CHECK: bb1:
+    // CHECK: path_b
+    // CHECK: bb2:
+    // CHECK: path_a
+}
+
+// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1}
diff --git a/tests/codegen/hint/likely.rs b/tests/codegen/hint/likely.rs
new file mode 100644
index 00000000000..2f589cc99d2
--- /dev/null
+++ b/tests/codegen/hint/likely.rs
@@ -0,0 +1,81 @@
+//@ compile-flags: -O
+#![crate_type = "lib"]
+#![feature(likely_unlikely)]
+
+use std::hint::likely;
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_a() {
+    println!("path a");
+}
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_b() {
+    println!("path b");
+}
+
+#[no_mangle]
+pub fn test1(x: bool) {
+    if likely(x) {
+        path_a();
+    } else {
+        path_b();
+    }
+
+    // CHECK-LABEL: @test1(
+    // CHECK: br i1 %x, label %bb2, label %bb3, !prof ![[NUM:[0-9]+]]
+    // CHECK: bb3:
+    // CHECK: path_b
+    // CHECK: bb2:
+    // CHECK: path_a
+}
+
+#[no_mangle]
+pub fn test2(x: i32) {
+    match likely(x > 0) {
+        true => path_a(),
+        false => path_b(),
+    }
+
+    // CHECK-LABEL: @test2(
+    // CHECK: br i1 %_2, label %bb2, label %bb3, !prof ![[NUM]]
+    // CHECK: bb3:
+    // CHECK: path_b
+    // CHECK: bb2:
+    // CHECK: path_a
+}
+
+#[no_mangle]
+pub fn test3(x: i8) {
+    match likely(x < 7) {
+        true => path_a(),
+        _ => path_b(),
+    }
+
+    // CHECK-LABEL: @test3(
+    // CHECK: br i1 %_2, label %bb2, label %bb3, !prof ![[NUM]]
+    // CHECK: bb3:
+    // CHECK: path_b
+    // CHECK: bb2:
+    // CHECK: path_a
+}
+
+#[no_mangle]
+pub fn test4(x: u64) {
+    match likely(x != 33) {
+        false => path_a(),
+        _ => path_b(),
+    }
+
+    // CHECK-LABEL: @test4(
+    // CHECK: br i1 %0, label %bb3, label %bb2, !prof ![[NUM2:[0-9]+]]
+    // CHECK: bb3:
+    // CHECK: path_a
+    // CHECK: bb2:
+    // CHECK: path_b
+}
+
+// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1}
+// CHECK: ![[NUM2]] = !{!"branch_weights", {{(!"expected", )?}}i32 1, i32 2000}
diff --git a/tests/codegen/hint/unlikely.rs b/tests/codegen/hint/unlikely.rs
new file mode 100644
index 00000000000..328533f3081
--- /dev/null
+++ b/tests/codegen/hint/unlikely.rs
@@ -0,0 +1,80 @@
+//@ compile-flags: -O
+#![crate_type = "lib"]
+#![feature(likely_unlikely)]
+
+use std::hint::unlikely;
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_a() {
+    println!("path a");
+}
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_b() {
+    println!("path b");
+}
+
+#[no_mangle]
+pub fn test1(x: bool) {
+    if unlikely(x) {
+        path_a();
+    } else {
+        path_b();
+    }
+
+    // CHECK-LABEL: @test1(
+    // CHECK: br i1 %x, label %bb2, label %bb4, !prof ![[NUM:[0-9]+]]
+    // CHECK: bb4:
+    // CHECK: path_b
+    // CHECK: bb2:
+    // CHECK: path_a
+}
+
+#[no_mangle]
+pub fn test2(x: i32) {
+    match unlikely(x > 0) {
+        true => path_a(),
+        false => path_b(),
+    }
+
+    // CHECK-LABEL: @test2(
+    // CHECK: br i1 %_2, label %bb2, label %bb4, !prof ![[NUM]]
+    // CHECK: bb4:
+    // CHECK: path_b
+    // CHECK: bb2:
+    // CHECK: path_a
+}
+
+#[no_mangle]
+pub fn test3(x: i8) {
+    match unlikely(x < 7) {
+        true => path_a(),
+        _ => path_b(),
+    }
+
+    // CHECK-LABEL: @test3(
+    // CHECK: br i1 %_2, label %bb2, label %bb4, !prof ![[NUM]]
+    // CHECK: bb4:
+    // CHECK: path_b
+    // CHECK: bb2:
+    // CHECK: path_a
+}
+
+#[no_mangle]
+pub fn test4(x: u64) {
+    match unlikely(x != 33) {
+        false => path_a(),
+        _ => path_b(),
+    }
+
+    // CHECK-LABEL: @test4(
+    // CHECK: br i1 %0, label %bb4, label %bb2, !prof ![[NUM2:[0-9]+]]
+    // CHECK: bb4:
+    // CHECK: path_a
+    // CHECK: bb2:
+    // CHECK: path_b
+}
+
+// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 1, i32 2000}
diff --git a/tests/codegen/intrinsics/transmute-niched.rs b/tests/codegen/intrinsics/transmute-niched.rs
index f5b7bd2efea..88119ccb8b2 100644
--- a/tests/codegen/intrinsics/transmute-niched.rs
+++ b/tests/codegen/intrinsics/transmute-niched.rs
@@ -17,12 +17,13 @@ pub enum SmallEnum {
 // CHECK-LABEL: @check_to_enum(
 #[no_mangle]
 pub unsafe fn check_to_enum(x: i8) -> SmallEnum {
-    // OPT: %0 = icmp uge i8 %x, 10
-    // OPT: call void @llvm.assume(i1 %0)
-    // OPT: %1 = icmp ule i8 %x, 12
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i8 %x, 10
+    // OPT: %1 = icmp ule i8 %0, 2
     // OPT: call void @llvm.assume(i1 %1)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: ret i8 %x
 
     transmute(x)
@@ -31,12 +32,13 @@ pub unsafe fn check_to_enum(x: i8) -> SmallEnum {
 // CHECK-LABEL: @check_from_enum(
 #[no_mangle]
 pub unsafe fn check_from_enum(x: SmallEnum) -> i8 {
-    // OPT: %0 = icmp uge i8 %x, 10
-    // OPT: call void @llvm.assume(i1 %0)
-    // OPT: %1 = icmp ule i8 %x, 12
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i8 %x, 10
+    // OPT: %1 = icmp ule i8 %0, 2
     // OPT: call void @llvm.assume(i1 %1)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: ret i8 %x
 
     transmute(x)
@@ -45,12 +47,13 @@ pub unsafe fn check_from_enum(x: SmallEnum) -> i8 {
 // CHECK-LABEL: @check_to_ordering(
 #[no_mangle]
 pub unsafe fn check_to_ordering(x: u8) -> std::cmp::Ordering {
-    // OPT: %0 = icmp uge i8 %x, -1
-    // OPT: %1 = icmp ule i8 %x, 1
-    // OPT: %2 = or i1 %0, %1
-    // OPT: call void @llvm.assume(i1 %2)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i8 %x, -1
+    // OPT: %1 = icmp ule i8 %0, 2
+    // OPT: call void @llvm.assume(i1 %1)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: ret i8 %x
 
     transmute(x)
@@ -59,12 +62,13 @@ pub unsafe fn check_to_ordering(x: u8) -> std::cmp::Ordering {
 // CHECK-LABEL: @check_from_ordering(
 #[no_mangle]
 pub unsafe fn check_from_ordering(x: std::cmp::Ordering) -> u8 {
-    // OPT: %0 = icmp uge i8 %x, -1
-    // OPT: %1 = icmp ule i8 %x, 1
-    // OPT: %2 = or i1 %0, %1
-    // OPT: call void @llvm.assume(i1 %2)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i8 %x, -1
+    // OPT: %1 = icmp ule i8 %0, 2
+    // OPT: call void @llvm.assume(i1 %1)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: ret i8 %x
 
     transmute(x)
@@ -98,14 +102,15 @@ pub enum Minus100ToPlus100 {
 // CHECK-LABEL: @check_enum_from_char(
 #[no_mangle]
 pub unsafe fn check_enum_from_char(x: char) -> Minus100ToPlus100 {
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // OPT: %0 = icmp ule i32 %x, 1114111
     // OPT: call void @llvm.assume(i1 %0)
-    // OPT: %1 = icmp uge i32 %x, -100
-    // OPT: %2 = icmp ule i32 %x, 100
-    // OPT: %3 = or i1 %1, %2
-    // OPT: call void @llvm.assume(i1 %3)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // OPT: %1 = sub i32 %x, -100
+    // OPT: %2 = icmp ule i32 %1, 200
+    // OPT: call void @llvm.assume(i1 %2)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: ret i32 %x
 
     transmute(x)
@@ -114,14 +119,15 @@ pub unsafe fn check_enum_from_char(x: char) -> Minus100ToPlus100 {
 // CHECK-LABEL: @check_enum_to_char(
 #[no_mangle]
 pub unsafe fn check_enum_to_char(x: Minus100ToPlus100) -> char {
-    // OPT: %0 = icmp uge i32 %x, -100
-    // OPT: %1 = icmp ule i32 %x, 100
-    // OPT: %2 = or i1 %0, %1
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i32 %x, -100
+    // OPT: %1 = icmp ule i32 %0, 200
+    // OPT: call void @llvm.assume(i1 %1)
+    // OPT: %2 = icmp ule i32 %x, 1114111
     // OPT: call void @llvm.assume(i1 %2)
-    // OPT: %3 = icmp ule i32 %x, 1114111
-    // OPT: call void @llvm.assume(i1 %3)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: ret i32 %x
 
     transmute(x)
@@ -130,16 +136,20 @@ pub unsafe fn check_enum_to_char(x: Minus100ToPlus100) -> char {
 // CHECK-LABEL: @check_swap_pair(
 #[no_mangle]
 pub unsafe fn check_swap_pair(x: (char, NonZero<u32>)) -> (NonZero<u32>, char) {
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // OPT: %0 = icmp ule i32 %x.0, 1114111
     // OPT: call void @llvm.assume(i1 %0)
-    // OPT: %1 = icmp uge i32 %x.0, 1
-    // OPT: call void @llvm.assume(i1 %1)
-    // OPT: %2 = icmp uge i32 %x.1, 1
+    // OPT: %1 = sub i32 %x.0, 1
+    // OPT: %2 = icmp ule i32 %1, -2
     // OPT: call void @llvm.assume(i1 %2)
-    // OPT: %3 = icmp ule i32 %x.1, 1114111
-    // OPT: call void @llvm.assume(i1 %3)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // OPT: %3 = sub i32 %x.1, 1
+    // OPT: %4 = icmp ule i32 %3, -2
+    // OPT: call void @llvm.assume(i1 %4)
+    // OPT: %5 = icmp ule i32 %x.1, 1114111
+    // OPT: call void @llvm.assume(i1 %5)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: %[[P1:.+]] = insertvalue { i32, i32 } poison, i32 %x.0, 0
     // CHECK: %[[P2:.+]] = insertvalue { i32, i32 } %[[P1]], i32 %x.1, 1
     // CHECK: ret { i32, i32 } %[[P2]]
@@ -150,14 +160,15 @@ pub unsafe fn check_swap_pair(x: (char, NonZero<u32>)) -> (NonZero<u32>, char) {
 // CHECK-LABEL: @check_bool_from_ordering(
 #[no_mangle]
 pub unsafe fn check_bool_from_ordering(x: std::cmp::Ordering) -> bool {
-    // OPT: %0 = icmp uge i8 %x, -1
-    // OPT: %1 = icmp ule i8 %x, 1
-    // OPT: %2 = or i1 %0, %1
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i8 %x, -1
+    // OPT: %1 = icmp ule i8 %0, 2
+    // OPT: call void @llvm.assume(i1 %1)
+    // OPT: %2 = icmp ule i8 %x, 1
     // OPT: call void @llvm.assume(i1 %2)
-    // OPT: %3 = icmp ule i8 %x, 1
-    // OPT: call void @llvm.assume(i1 %3)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: %[[R:.+]] = trunc i8 %x to i1
     // CHECK: ret i1 %[[R]]
 
@@ -168,14 +179,15 @@ pub unsafe fn check_bool_from_ordering(x: std::cmp::Ordering) -> bool {
 #[no_mangle]
 pub unsafe fn check_bool_to_ordering(x: bool) -> std::cmp::Ordering {
     // CHECK: %_0 = zext i1 %x to i8
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // OPT: %0 = icmp ule i8 %_0, 1
     // OPT: call void @llvm.assume(i1 %0)
-    // OPT: %1 = icmp uge i8 %_0, -1
-    // OPT: %2 = icmp ule i8 %_0, 1
-    // OPT: %3 = or i1 %1, %2
-    // OPT: call void @llvm.assume(i1 %3)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // OPT: %1 = sub i8 %_0, -1
+    // OPT: %2 = icmp ule i8 %1, 2
+    // OPT: call void @llvm.assume(i1 %2)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: ret i8 %_0
 
     transmute(x)
diff --git a/tests/codegen/mainsubprogramstart.rs b/tests/codegen/mainsubprogramstart.rs
deleted file mode 100644
index 0bcb311644d..00000000000
--- a/tests/codegen/mainsubprogramstart.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-//@ ignore-apple
-//@ ignore-wasi wasi codegens the main symbol differently
-
-//@ compile-flags: -g -C no-prepopulate-passes
-
-#![feature(start)]
-
-// CHECK-LABEL: @main
-// CHECK: {{.*}}DISubprogram{{.*}}name: "start",{{.*}}DI{{(SP)?}}FlagMainSubprogram{{.*}}
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
-    return 0;
-}
diff --git a/tests/codegen/overaligned-constant.rs b/tests/codegen/overaligned-constant.rs
index 7cd8d19c211..e5540aca387 100644
--- a/tests/codegen/overaligned-constant.rs
+++ b/tests/codegen/overaligned-constant.rs
@@ -17,8 +17,6 @@ pub fn overaligned_constant() {
     // CHECK-LABEL: @overaligned_constant
     // CHECK: [[full:%_.*]] = alloca [32 x i8], align 8
     // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[full]], ptr align 8 @0, i64 32, i1 false)
-    // CHECK: %b.0 = load i32, ptr @0, align 4
-    // CHECK: %b.1 = load i32, ptr getelementptr inbounds ({{.*}}), align 4
     let mut s = S(1);
 
     s.0 = 3;
diff --git a/tests/codegen/slice-init.rs b/tests/codegen/slice-init.rs
index 1c2dd3e8875..b36a5b5de3d 100644
--- a/tests/codegen/slice-init.rs
+++ b/tests/codegen/slice-init.rs
@@ -2,6 +2,8 @@
 
 #![crate_type = "lib"]
 
+use std::mem::MaybeUninit;
+
 // CHECK-LABEL: @zero_sized_elem
 #[no_mangle]
 pub fn zero_sized_elem() {
@@ -76,17 +78,64 @@ pub fn u16_init_one_bytes() -> [u16; N] {
     [const { u16::from_be_bytes([1, 1]) }; N]
 }
 
-// FIXME: undef bytes can just be initialized with the same value as the
-// defined bytes, if the defines bytes are all the same.
 // CHECK-LABEL: @option_none_init
 #[no_mangle]
 pub fn option_none_init() -> [Option<u8>; N] {
     // CHECK-NOT: select
+    // CHECK-NOT: br
+    // CHECK-NOT: switch
+    // CHECK-NOT: icmp
+    // CHECK: call void @llvm.memset.p0
+    [const { None }; N]
+}
+
+// If there is partial provenance or some bytes are initialized and some are not,
+// we can't really do better than initialize bytes or groups of bytes together.
+// CHECK-LABEL: @option_maybe_uninit_init
+#[no_mangle]
+pub fn option_maybe_uninit_init() -> [MaybeUninit<u16>; N] {
+    // CHECK-NOT: select
+    // CHECK: br label %repeat_loop_header{{.*}}
+    // CHECK-NOT: switch
+    // CHECK: icmp
+    // CHECK-NOT: call void @llvm.memset.p0
+    [const {
+        let mut val: MaybeUninit<u16> = MaybeUninit::uninit();
+        let ptr = val.as_mut_ptr() as *mut u8;
+        unsafe {
+            ptr.write(0);
+        }
+        val
+    }; N]
+}
+
+#[repr(packed)]
+struct Packed {
+    start: u8,
+    ptr: &'static (),
+    rest: u16,
+    rest2: u8,
+}
+
+// If there is partial provenance or some bytes are initialized and some are not,
+// we can't really do better than initialize bytes or groups of bytes together.
+// CHECK-LABEL: @option_maybe_uninit_provenance
+#[no_mangle]
+pub fn option_maybe_uninit_provenance() -> [MaybeUninit<Packed>; N] {
+    // CHECK-NOT: select
     // CHECK: br label %repeat_loop_header{{.*}}
     // CHECK-NOT: switch
     // CHECK: icmp
     // CHECK-NOT: call void @llvm.memset.p0
-    [None; N]
+    [const {
+        let mut val: MaybeUninit<Packed> = MaybeUninit::uninit();
+        unsafe {
+            let ptr = &raw mut (*val.as_mut_ptr()).ptr;
+            static HAS_ADDR: () = ();
+            ptr.write_unaligned(&HAS_ADDR);
+        }
+        val
+    }; N]
 }
 
 // Use an opaque function to prevent rustc from removing useless drops.
diff --git a/tests/codegen/transmute-optimized.rs b/tests/codegen/transmute-optimized.rs
index 11bd0523788..de54eecf0c0 100644
--- a/tests/codegen/transmute-optimized.rs
+++ b/tests/codegen/transmute-optimized.rs
@@ -110,3 +110,11 @@ pub fn char_is_negative(c: char) -> bool {
     let x: i32 = unsafe { std::mem::transmute(c) };
     x < 0
 }
+
+// CHECK-LABEL: i1 @transmute_to_char_is_negative(i32
+#[no_mangle]
+pub fn transmute_to_char_is_negative(x: i32) -> bool {
+    // CHECK: ret i1 false
+    let _c: char = unsafe { std::mem::transmute(x) };
+    x < 0
+}
diff --git a/tests/crashes/130779.rs b/tests/crashes/130779.rs
deleted file mode 100644
index f0fd81fff44..00000000000
--- a/tests/crashes/130779.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-//@ known-bug: #130779
-#![feature(never_patterns)]
-
-enum E { A }
-
-fn main() {
-    match E::A {
-        ! |
-        if true => {}
-    }
-}
diff --git a/tests/crashes/133063.rs b/tests/crashes/133063.rs
deleted file mode 100644
index 132b5486170..00000000000
--- a/tests/crashes/133063.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ known-bug: #133063
-
-fn foo(x: !) {
-    match x {
-        (! | !) if false => {}
-        _ => {}
-    }
-}
diff --git a/tests/crashes/133117.rs b/tests/crashes/133117.rs
deleted file mode 100644
index 751c82626d5..00000000000
--- a/tests/crashes/133117.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ known-bug: #133117
-
-fn main() {
-    match () {
-        (!|!) if true => {}
-        (!|!) if true => {}
-    }
-}
diff --git a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir
index 8d9176ef301..a467987e886 100644
--- a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir
+++ b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir
@@ -7,7 +7,8 @@ fn main() -> () {
     let mut _5: u32;
     let mut _6: *mut usize;
     let _7: usize;
-    let mut _8: bool;
+    let mut _8: usize;
+    let mut _9: bool;
     scope 1 {
         debug x => _1;
         let mut _2: usize;
@@ -40,8 +41,9 @@ fn main() -> () {
         StorageDead(_6);
         StorageLive(_7);
         _7 = copy _2;
-        _8 = Lt(copy _7, const 3_usize);
-        assert(move _8, "index out of bounds: the length is {} but the index is {}", const 3_usize, copy _7) -> [success: bb2, unwind unreachable];
+        _8 = Len(_1);
+        _9 = Lt(copy _7, copy _8);
+        assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind unreachable];
     }
 
     bb2: {
diff --git a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
index e1df0e3e2a3..bd7365543bd 100644
--- a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
+++ b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
@@ -7,7 +7,8 @@ fn main() -> () {
     let mut _5: u32;
     let mut _6: *mut usize;
     let _7: usize;
-    let mut _8: bool;
+    let mut _8: usize;
+    let mut _9: bool;
     scope 1 {
         debug x => _1;
         let mut _2: usize;
@@ -40,8 +41,9 @@ fn main() -> () {
         StorageDead(_6);
         StorageLive(_7);
         _7 = copy _2;
-        _8 = Lt(copy _7, const 3_usize);
-        assert(move _8, "index out of bounds: the length is {} but the index is {}", const 3_usize, copy _7) -> [success: bb2, unwind continue];
+        _8 = Len(_1);
+        _9 = Lt(copy _7, copy _8);
+        assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind continue];
     }
 
     bb2: {
diff --git a/tests/mir-opt/building/custom/arrays.arrays.built.after.mir b/tests/mir-opt/building/custom/arrays.arrays.built.after.mir
new file mode 100644
index 00000000000..30d11e31e4d
--- /dev/null
+++ b/tests/mir-opt/building/custom/arrays.arrays.built.after.mir
@@ -0,0 +1,14 @@
+// MIR for `arrays` after built
+
+fn arrays() -> usize {
+    let mut _0: usize;
+    let mut _1: [i32; C];
+    let mut _2: usize;
+
+    bb0: {
+        _1 = [const 5_i32; C];
+        _2 = Len(_1);
+        _0 = copy _2;
+        return;
+    }
+}
diff --git a/tests/mir-opt/building/custom/arrays.rs b/tests/mir-opt/building/custom/arrays.rs
new file mode 100644
index 00000000000..4bd6f93e113
--- /dev/null
+++ b/tests/mir-opt/building/custom/arrays.rs
@@ -0,0 +1,22 @@
+// skip-filecheck
+#![feature(custom_mir, core_intrinsics)]
+
+extern crate core;
+use core::intrinsics::mir::*;
+
+// EMIT_MIR arrays.arrays.built.after.mir
+#[custom_mir(dialect = "built")]
+fn arrays<const C: usize>() -> usize {
+    mir! {
+        {
+            let x = [5_i32; C];
+            let c = Len(x);
+            RET = c;
+            Return()
+        }
+    }
+}
+
+fn main() {
+    assert_eq!(arrays::<20>(), 20);
+}
diff --git a/tests/mir-opt/building/index_array_and_slice.index_array.built.after.mir b/tests/mir-opt/building/index_array_and_slice.index_array.built.after.mir
deleted file mode 100644
index d28a2031013..00000000000
--- a/tests/mir-opt/building/index_array_and_slice.index_array.built.after.mir
+++ /dev/null
@@ -1,31 +0,0 @@
-// MIR for `index_array` after built
-
-fn index_array(_1: &[i32; 7], _2: usize) -> &i32 {
-    debug array => _1;
-    debug index => _2;
-    let mut _0: &i32;
-    let _3: &i32;
-    let _4: usize;
-    let mut _5: bool;
-
-    bb0: {
-        StorageLive(_3);
-        StorageLive(_4);
-        _4 = copy _2;
-        FakeRead(ForIndex, (*_1));
-        _5 = Lt(copy _4, const 7_usize);
-        assert(move _5, "index out of bounds: the length is {} but the index is {}", const 7_usize, copy _4) -> [success: bb1, unwind: bb2];
-    }
-
-    bb1: {
-        _3 = &(*_1)[_4];
-        _0 = &(*_3);
-        StorageDead(_4);
-        StorageDead(_3);
-        return;
-    }
-
-    bb2 (cleanup): {
-        resume;
-    }
-}
diff --git a/tests/mir-opt/building/index_array_and_slice.index_const_generic_array.built.after.mir b/tests/mir-opt/building/index_array_and_slice.index_const_generic_array.built.after.mir
deleted file mode 100644
index e9627532c38..00000000000
--- a/tests/mir-opt/building/index_array_and_slice.index_const_generic_array.built.after.mir
+++ /dev/null
@@ -1,31 +0,0 @@
-// MIR for `index_const_generic_array` after built
-
-fn index_const_generic_array(_1: &[i32; N], _2: usize) -> &i32 {
-    debug array => _1;
-    debug index => _2;
-    let mut _0: &i32;
-    let _3: &i32;
-    let _4: usize;
-    let mut _5: bool;
-
-    bb0: {
-        StorageLive(_3);
-        StorageLive(_4);
-        _4 = copy _2;
-        FakeRead(ForIndex, (*_1));
-        _5 = Lt(copy _4, const N);
-        assert(move _5, "index out of bounds: the length is {} but the index is {}", const N, copy _4) -> [success: bb1, unwind: bb2];
-    }
-
-    bb1: {
-        _3 = &(*_1)[_4];
-        _0 = &(*_3);
-        StorageDead(_4);
-        StorageDead(_3);
-        return;
-    }
-
-    bb2 (cleanup): {
-        resume;
-    }
-}
diff --git a/tests/mir-opt/building/index_array_and_slice.index_custom.built.after.mir b/tests/mir-opt/building/index_array_and_slice.index_custom.built.after.mir
deleted file mode 100644
index 00f2b7e07d5..00000000000
--- a/tests/mir-opt/building/index_array_and_slice.index_custom.built.after.mir
+++ /dev/null
@@ -1,34 +0,0 @@
-// MIR for `index_custom` after built
-
-fn index_custom(_1: &WithSliceTail, _2: usize) -> &i32 {
-    debug custom => _1;
-    debug index => _2;
-    let mut _0: &i32;
-    let _3: &i32;
-    let _4: usize;
-    let mut _5: *const [i32];
-    let mut _6: usize;
-    let mut _7: bool;
-
-    bb0: {
-        StorageLive(_3);
-        StorageLive(_4);
-        _4 = copy _2;
-        _5 = &raw const ((*_1).1: [i32]);
-        _6 = PtrMetadata(move _5);
-        _7 = Lt(copy _4, copy _6);
-        assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _4) -> [success: bb1, unwind: bb2];
-    }
-
-    bb1: {
-        _3 = &((*_1).1: [i32])[_4];
-        _0 = &(*_3);
-        StorageDead(_4);
-        StorageDead(_3);
-        return;
-    }
-
-    bb2 (cleanup): {
-        resume;
-    }
-}
diff --git a/tests/mir-opt/building/index_array_and_slice.index_mut_slice.built.after.mir b/tests/mir-opt/building/index_array_and_slice.index_mut_slice.built.after.mir
deleted file mode 100644
index cb0b2f600c8..00000000000
--- a/tests/mir-opt/building/index_array_and_slice.index_mut_slice.built.after.mir
+++ /dev/null
@@ -1,34 +0,0 @@
-// MIR for `index_mut_slice` after built
-
-fn index_mut_slice(_1: &mut [i32], _2: usize) -> &i32 {
-    debug slice => _1;
-    debug index => _2;
-    let mut _0: &i32;
-    let _3: &i32;
-    let _4: usize;
-    let mut _5: *const [i32];
-    let mut _6: usize;
-    let mut _7: bool;
-
-    bb0: {
-        StorageLive(_3);
-        StorageLive(_4);
-        _4 = copy _2;
-        _5 = &raw const (*_1);
-        _6 = PtrMetadata(move _5);
-        _7 = Lt(copy _4, copy _6);
-        assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _4) -> [success: bb1, unwind: bb2];
-    }
-
-    bb1: {
-        _3 = &(*_1)[_4];
-        _0 = &(*_3);
-        StorageDead(_4);
-        StorageDead(_3);
-        return;
-    }
-
-    bb2 (cleanup): {
-        resume;
-    }
-}
diff --git a/tests/mir-opt/building/index_array_and_slice.index_slice.built.after.mir b/tests/mir-opt/building/index_array_and_slice.index_slice.built.after.mir
deleted file mode 100644
index 0911df59049..00000000000
--- a/tests/mir-opt/building/index_array_and_slice.index_slice.built.after.mir
+++ /dev/null
@@ -1,32 +0,0 @@
-// MIR for `index_slice` after built
-
-fn index_slice(_1: &[i32], _2: usize) -> &i32 {
-    debug slice => _1;
-    debug index => _2;
-    let mut _0: &i32;
-    let _3: &i32;
-    let _4: usize;
-    let mut _5: usize;
-    let mut _6: bool;
-
-    bb0: {
-        StorageLive(_3);
-        StorageLive(_4);
-        _4 = copy _2;
-        _5 = PtrMetadata(copy _1);
-        _6 = Lt(copy _4, copy _5);
-        assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind: bb2];
-    }
-
-    bb1: {
-        _3 = &(*_1)[_4];
-        _0 = &(*_3);
-        StorageDead(_4);
-        StorageDead(_3);
-        return;
-    }
-
-    bb2 (cleanup): {
-        resume;
-    }
-}
diff --git a/tests/mir-opt/building/index_array_and_slice.rs b/tests/mir-opt/building/index_array_and_slice.rs
deleted file mode 100644
index 16d0b983132..00000000000
--- a/tests/mir-opt/building/index_array_and_slice.rs
+++ /dev/null
@@ -1,71 +0,0 @@
-//@ compile-flags: -C opt-level=0
-
-// EMIT_MIR index_array_and_slice.index_array.built.after.mir
-fn index_array(array: &[i32; 7], index: usize) -> &i32 {
-    // CHECK: bb0:
-    // CHECK: [[LT:_.+]] = Lt(copy _2, const 7_usize);
-    // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", const 7_usize, copy _2) -> [success: bb1, unwind
-
-    // CHECK: bb1:
-    // CHECK: _0 = &(*_1)[_2];
-    &array[index]
-}
-
-// EMIT_MIR index_array_and_slice.index_const_generic_array.built.after.mir
-fn index_const_generic_array<const N: usize>(array: &[i32; N], index: usize) -> &i32 {
-    // CHECK: bb0:
-    // CHECK: [[LT:_.+]] = Lt(copy _2, const N);
-    // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", const N, copy _2) -> [success: bb1, unwind
-
-    // CHECK: bb1:
-    // CHECK: _0 = &(*_1)[_2];
-    &array[index]
-}
-
-// EMIT_MIR index_array_and_slice.index_slice.built.after.mir
-fn index_slice(slice: &[i32], index: usize) -> &i32 {
-    // CHECK: bb0:
-    // CHECK: [[LEN:_.+]] = PtrMetadata(copy _1);
-    // CHECK: [[LT:_.+]] = Lt(copy _2, copy [[LEN]]);
-    // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", move [[LEN]], copy _2) -> [success: bb1,
-
-    // CHECK: bb1:
-    // CHECK: _0 = &(*_1)[_2];
-    &slice[index]
-}
-
-// EMIT_MIR index_array_and_slice.index_mut_slice.built.after.mir
-fn index_mut_slice(slice: &mut [i32], index: usize) -> &i32 {
-    // While the filecheck here is identical to the above test, the emitted MIR is different.
-    // This cannot `copy _1` in the *built* MIR, only in the *runtime* MIR.
-
-    // CHECK: bb0:
-    // CHECK: [[LEN:_.+]] = PtrMetadata(copy _1);
-    // CHECK: [[LT:_.+]] = Lt(copy _2, copy [[LEN]]);
-    // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", move [[LEN]], copy _2) -> [success: bb1,
-
-    // CHECK: bb1:
-    // CHECK: _0 = &(*_1)[_2];
-    &slice[index]
-}
-
-struct WithSliceTail(f64, [i32]);
-
-// EMIT_MIR index_array_and_slice.index_custom.built.after.mir
-fn index_custom(custom: &WithSliceTail, index: usize) -> &i32 {
-    // CHECK: bb0:
-    // CHECK: [[PTR:_.+]] = &raw const ((*_1).1: [i32]);
-    // CHECK: [[LEN:_.+]] = PtrMetadata(move [[PTR]]);
-    // CHECK: [[LT:_.+]] = Lt(copy _2, copy [[LEN]]);
-    // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", move [[LEN]], copy _2) -> [success: bb1,
-
-    // CHECK: bb1:
-    // CHECK: _0 = &((*_1).1: [i32])[_2];
-    &custom.1[index]
-}
-
-fn main() {
-    index_array(&[1, 2, 3, 4, 5, 6, 7], 3);
-    index_slice(&[1, 2, 3, 4, 5, 6, 7][..], 3);
-    _ = index_custom;
-}
diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff
index 3a5a8d00991..e754af95ce3 100644
--- a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff
@@ -6,7 +6,8 @@
       let _1: u32;
       let mut _2: [u32; 4];
       let _3: usize;
-      let mut _4: bool;
+      let mut _4: usize;
+      let mut _5: bool;
       scope 1 {
           debug x => _1;
       }
@@ -17,9 +18,11 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Lt(copy _3, const 4_usize);
--         assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind unreachable];
-+         _4 = const true;
+-         _4 = Len(_2);
+-         _5 = Lt(copy _3, copy _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable];
++         _4 = const 4_usize;
++         _5 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff
index 62d6e6007e5..e15a35c7fe9 100644
--- a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff
@@ -6,7 +6,8 @@
       let _1: u32;
       let mut _2: [u32; 4];
       let _3: usize;
-      let mut _4: bool;
+      let mut _4: usize;
+      let mut _5: bool;
       scope 1 {
           debug x => _1;
       }
@@ -17,9 +18,11 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Lt(copy _3, const 4_usize);
--         assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind continue];
-+         _4 = const true;
+-         _4 = Len(_2);
+-         _5 = Lt(copy _3, copy _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue];
++         _4 = const 4_usize;
++         _5 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff
index 3a5a8d00991..e754af95ce3 100644
--- a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff
@@ -6,7 +6,8 @@
       let _1: u32;
       let mut _2: [u32; 4];
       let _3: usize;
-      let mut _4: bool;
+      let mut _4: usize;
+      let mut _5: bool;
       scope 1 {
           debug x => _1;
       }
@@ -17,9 +18,11 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Lt(copy _3, const 4_usize);
--         assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind unreachable];
-+         _4 = const true;
+-         _4 = Len(_2);
+-         _5 = Lt(copy _3, copy _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable];
++         _4 = const 4_usize;
++         _5 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff
index 62d6e6007e5..e15a35c7fe9 100644
--- a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff
@@ -6,7 +6,8 @@
       let _1: u32;
       let mut _2: [u32; 4];
       let _3: usize;
-      let mut _4: bool;
+      let mut _4: usize;
+      let mut _5: bool;
       scope 1 {
           debug x => _1;
       }
@@ -17,9 +18,11 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Lt(copy _3, const 4_usize);
--         assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind continue];
-+         _4 = const true;
+-         _4 = Len(_2);
+-         _5 = Lt(copy _3, copy _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue];
++         _4 = const 4_usize;
++         _5 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff
index be42c4d60c8..15d30140367 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff
@@ -30,22 +30,19 @@
           StorageDead(_2);
           StorageDead(_3);
           StorageLive(_5);
--         StorageLive(_6);
-+         nop;
+          StorageLive(_6);
           _6 = const 3_usize;
--         _7 = PtrMetadata(copy _1);
+          _7 = Len((*_1));
 -         _8 = Lt(copy _6, copy _7);
 -         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable];
-+         _7 = const 3_usize;
-+         _8 = const false;
-+         assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind unreachable];
++         _8 = Lt(const 3_usize, copy _7);
++         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
 -         _5 = copy (*_1)[_6];
--         StorageDead(_6);
 +         _5 = copy (*_1)[3 of 4];
-+         nop;
+          StorageDead(_6);
           _0 = const ();
           StorageDead(_5);
           StorageDead(_1);
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff
index b51d0c0845f..dd411d84f9f 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff
@@ -30,22 +30,19 @@
           StorageDead(_2);
           StorageDead(_3);
           StorageLive(_5);
--         StorageLive(_6);
-+         nop;
+          StorageLive(_6);
           _6 = const 3_usize;
--         _7 = PtrMetadata(copy _1);
+          _7 = Len((*_1));
 -         _8 = Lt(copy _6, copy _7);
 -         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue];
-+         _7 = const 3_usize;
-+         _8 = const false;
-+         assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind continue];
++         _8 = Lt(const 3_usize, copy _7);
++         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
 -         _5 = copy (*_1)[_6];
--         StorageDead(_6);
 +         _5 = copy (*_1)[3 of 4];
-+         nop;
+          StorageDead(_6);
           _0 = const ();
           StorageDead(_5);
           StorageDead(_1);
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff
index be42c4d60c8..15d30140367 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff
@@ -30,22 +30,19 @@
           StorageDead(_2);
           StorageDead(_3);
           StorageLive(_5);
--         StorageLive(_6);
-+         nop;
+          StorageLive(_6);
           _6 = const 3_usize;
--         _7 = PtrMetadata(copy _1);
+          _7 = Len((*_1));
 -         _8 = Lt(copy _6, copy _7);
 -         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable];
-+         _7 = const 3_usize;
-+         _8 = const false;
-+         assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind unreachable];
++         _8 = Lt(const 3_usize, copy _7);
++         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
 -         _5 = copy (*_1)[_6];
--         StorageDead(_6);
 +         _5 = copy (*_1)[3 of 4];
-+         nop;
+          StorageDead(_6);
           _0 = const ();
           StorageDead(_5);
           StorageDead(_1);
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff
index b51d0c0845f..dd411d84f9f 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff
@@ -30,22 +30,19 @@
           StorageDead(_2);
           StorageDead(_3);
           StorageLive(_5);
--         StorageLive(_6);
-+         nop;
+          StorageLive(_6);
           _6 = const 3_usize;
--         _7 = PtrMetadata(copy _1);
+          _7 = Len((*_1));
 -         _8 = Lt(copy _6, copy _7);
 -         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue];
-+         _7 = const 3_usize;
-+         _8 = const false;
-+         assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind continue];
++         _8 = Lt(const 3_usize, copy _7);
++         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
 -         _5 = copy (*_1)[_6];
--         StorageDead(_6);
 +         _5 = copy (*_1)[3 of 4];
-+         nop;
+          StorageDead(_6);
           _0 = const ();
           StorageDead(_5);
           StorageDead(_1);
diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff
index 3569998b13f..49ea51deed6 100644
--- a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff
@@ -6,7 +6,8 @@
       let _1: u8;
       let mut _2: [u8; 5000];
       let _3: usize;
-      let mut _4: bool;
+      let mut _4: usize;
+      let mut _5: bool;
       scope 1 {
           debug x => _1;
       }
@@ -17,9 +18,11 @@
           _2 = [const 0_u8; 5000];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Lt(copy _3, const 5000_usize);
--         assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind unreachable];
-+         _4 = const true;
+-         _4 = Len(_2);
+-         _5 = Lt(copy _3, copy _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable];
++         _4 = const 5000_usize;
++         _5 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff
index 50b31c9ac13..103bfbcaf64 100644
--- a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff
@@ -6,7 +6,8 @@
       let _1: u8;
       let mut _2: [u8; 5000];
       let _3: usize;
-      let mut _4: bool;
+      let mut _4: usize;
+      let mut _5: bool;
       scope 1 {
           debug x => _1;
       }
@@ -17,9 +18,11 @@
           _2 = [const 0_u8; 5000];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Lt(copy _3, const 5000_usize);
--         assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind continue];
-+         _4 = const true;
+-         _4 = Len(_2);
+-         _5 = Lt(copy _3, copy _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue];
++         _4 = const 5000_usize;
++         _5 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff
index 3569998b13f..49ea51deed6 100644
--- a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff
@@ -6,7 +6,8 @@
       let _1: u8;
       let mut _2: [u8; 5000];
       let _3: usize;
-      let mut _4: bool;
+      let mut _4: usize;
+      let mut _5: bool;
       scope 1 {
           debug x => _1;
       }
@@ -17,9 +18,11 @@
           _2 = [const 0_u8; 5000];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Lt(copy _3, const 5000_usize);
--         assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind unreachable];
-+         _4 = const true;
+-         _4 = Len(_2);
+-         _5 = Lt(copy _3, copy _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable];
++         _4 = const 5000_usize;
++         _5 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff
index 50b31c9ac13..103bfbcaf64 100644
--- a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff
@@ -6,7 +6,8 @@
       let _1: u8;
       let mut _2: [u8; 5000];
       let _3: usize;
-      let mut _4: bool;
+      let mut _4: usize;
+      let mut _5: bool;
       scope 1 {
           debug x => _1;
       }
@@ -17,9 +18,11 @@
           _2 = [const 0_u8; 5000];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Lt(copy _3, const 5000_usize);
--         assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind continue];
-+         _4 = const true;
+-         _4 = Len(_2);
+-         _5 = Lt(copy _3, copy _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue];
++         _4 = const 5000_usize;
++         _5 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff
index a41668b6fa3..f7c1c2da01f 100644
--- a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff
@@ -7,7 +7,8 @@
       let mut _2: u32;
       let mut _3: [u32; 8];
       let _4: usize;
-      let mut _5: bool;
+      let mut _5: usize;
+      let mut _6: bool;
       scope 1 {
           debug x => _1;
       }
@@ -19,9 +20,11 @@
           _3 = [const 42_u32; 8];
           StorageLive(_4);
           _4 = const 2_usize;
--         _5 = Lt(copy _4, const 8_usize);
--         assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind unreachable];
-+         _5 = const true;
+-         _5 = Len(_3);
+-         _6 = Lt(copy _4, copy _5);
+-         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind unreachable];
++         _5 = const 8_usize;
++         _6 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff
index 2313084b49e..436773c8556 100644
--- a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff
@@ -7,7 +7,8 @@
       let mut _2: u32;
       let mut _3: [u32; 8];
       let _4: usize;
-      let mut _5: bool;
+      let mut _5: usize;
+      let mut _6: bool;
       scope 1 {
           debug x => _1;
       }
@@ -19,9 +20,11 @@
           _3 = [const 42_u32; 8];
           StorageLive(_4);
           _4 = const 2_usize;
--         _5 = Lt(copy _4, const 8_usize);
--         assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind continue];
-+         _5 = const true;
+-         _5 = Len(_3);
+-         _6 = Lt(copy _4, copy _5);
+-         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind continue];
++         _5 = const 8_usize;
++         _6 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff
index a41668b6fa3..f7c1c2da01f 100644
--- a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff
@@ -7,7 +7,8 @@
       let mut _2: u32;
       let mut _3: [u32; 8];
       let _4: usize;
-      let mut _5: bool;
+      let mut _5: usize;
+      let mut _6: bool;
       scope 1 {
           debug x => _1;
       }
@@ -19,9 +20,11 @@
           _3 = [const 42_u32; 8];
           StorageLive(_4);
           _4 = const 2_usize;
--         _5 = Lt(copy _4, const 8_usize);
--         assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind unreachable];
-+         _5 = const true;
+-         _5 = Len(_3);
+-         _6 = Lt(copy _4, copy _5);
+-         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind unreachable];
++         _5 = const 8_usize;
++         _6 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff
index 2313084b49e..436773c8556 100644
--- a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff
@@ -7,7 +7,8 @@
       let mut _2: u32;
       let mut _3: [u32; 8];
       let _4: usize;
-      let mut _5: bool;
+      let mut _5: usize;
+      let mut _6: bool;
       scope 1 {
           debug x => _1;
       }
@@ -19,9 +20,11 @@
           _3 = [const 42_u32; 8];
           StorageLive(_4);
           _4 = const 2_usize;
--         _5 = Lt(copy _4, const 8_usize);
--         assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind continue];
-+         _5 = const true;
+-         _5 = Len(_3);
+-         _6 = Lt(copy _4, copy _5);
+-         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind continue];
++         _5 = const 8_usize;
++         _6 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff
index 0798b303929..8a8ea5b7e20 100644
--- a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff
@@ -30,12 +30,11 @@
           StorageDead(_3);
           StorageLive(_6);
           _6 = const 1_usize;
--         _7 = PtrMetadata(copy _2);
+          _7 = Len((*_2));
 -         _8 = Lt(copy _6, copy _7);
 -         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable];
-+         _7 = const 3_usize;
-+         _8 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable];
++         _8 = Lt(const 1_usize, copy _7);
++         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 1_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff
index c0b3d4d3219..f0c844884f6 100644
--- a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff
@@ -30,12 +30,11 @@
           StorageDead(_3);
           StorageLive(_6);
           _6 = const 1_usize;
--         _7 = PtrMetadata(copy _2);
+          _7 = Len((*_2));
 -         _8 = Lt(copy _6, copy _7);
 -         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue];
-+         _7 = const 3_usize;
-+         _8 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue];
++         _8 = Lt(const 1_usize, copy _7);
++         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 1_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff
index 0798b303929..8a8ea5b7e20 100644
--- a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff
@@ -30,12 +30,11 @@
           StorageDead(_3);
           StorageLive(_6);
           _6 = const 1_usize;
--         _7 = PtrMetadata(copy _2);
+          _7 = Len((*_2));
 -         _8 = Lt(copy _6, copy _7);
 -         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable];
-+         _7 = const 3_usize;
-+         _8 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable];
++         _8 = Lt(const 1_usize, copy _7);
++         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 1_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff
index c0b3d4d3219..f0c844884f6 100644
--- a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff
@@ -30,12 +30,11 @@
           StorageDead(_3);
           StorageLive(_6);
           _6 = const 1_usize;
--         _7 = PtrMetadata(copy _2);
+          _7 = Len((*_2));
 -         _8 = Lt(copy _6, copy _7);
 -         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue];
-+         _7 = const 3_usize;
-+         _8 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue];
++         _8 = Lt(const 1_usize, copy _7);
++         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 1_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-abort.diff b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-abort.diff
index 689083dfc1d..6d967257df1 100644
--- a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-abort.diff
+++ b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-abort.diff
@@ -18,7 +18,8 @@
       let mut _15: !;
       let mut _17: i32;
       let _18: usize;
-      let mut _19: bool;
+      let mut _19: usize;
+      let mut _20: bool;
       scope 1 {
           debug sum => _1;
           let _2: [i32; 4];
@@ -91,10 +92,11 @@
           StorageLive(_17);
 -         StorageLive(_18);
 -         _18 = copy _16;
--         _19 = Lt(copy _18, const 4_usize);
--         assert(move _19, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _18) -> [success: bb8, unwind unreachable];
-+         _19 = Lt(copy _16, const 4_usize);
-+         assert(move _19, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _16) -> [success: bb8, unwind unreachable];
+          _19 = Len(_2);
+-         _20 = Lt(copy _18, copy _19);
+-         assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, copy _18) -> [success: bb8, unwind unreachable];
++         _20 = Lt(copy _16, copy _19);
++         assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, copy _16) -> [success: bb8, unwind unreachable];
       }
   
       bb7: {
diff --git a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff
index 7f768a9f834..3580c87c469 100644
--- a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff
+++ b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff
@@ -18,7 +18,8 @@
       let mut _15: !;
       let mut _17: i32;
       let _18: usize;
-      let mut _19: bool;
+      let mut _19: usize;
+      let mut _20: bool;
       scope 1 {
           debug sum => _1;
           let _2: [i32; 4];
@@ -91,10 +92,11 @@
           StorageLive(_17);
 -         StorageLive(_18);
 -         _18 = copy _16;
--         _19 = Lt(copy _18, const 4_usize);
--         assert(move _19, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _18) -> [success: bb8, unwind continue];
-+         _19 = Lt(copy _16, const 4_usize);
-+         assert(move _19, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _16) -> [success: bb8, unwind continue];
+          _19 = Len(_2);
+-         _20 = Lt(copy _18, copy _19);
+-         assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, copy _18) -> [success: bb8, unwind continue];
++         _20 = Lt(copy _16, copy _19);
++         assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, copy _16) -> [success: bb8, unwind continue];
       }
   
       bb7: {
diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff
index 0275d7e8a0d..a46daef435f 100644
--- a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff
@@ -6,7 +6,8 @@
       let _1: u32;
       let mut _2: [u32; 4];
       let _3: usize;
-      let mut _4: bool;
+      let mut _4: usize;
+      let mut _5: bool;
       scope 1 {
           debug x => _1;
       }
@@ -17,9 +18,11 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Lt(copy _3, const 4_usize);
--         assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind unreachable];
-+         _4 = const true;
+-         _4 = Len(_2);
+-         _5 = Lt(copy _3, copy _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable];
++         _4 = const 4_usize;
++         _5 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff
index 490ed4b55a1..1a4e15b45fa 100644
--- a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff
@@ -6,7 +6,8 @@
       let _1: u32;
       let mut _2: [u32; 4];
       let _3: usize;
-      let mut _4: bool;
+      let mut _4: usize;
+      let mut _5: bool;
       scope 1 {
           debug x => _1;
       }
@@ -17,9 +18,11 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Lt(copy _3, const 4_usize);
--         assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind continue];
-+         _4 = const true;
+-         _4 = Len(_2);
+-         _5 = Lt(copy _3, copy _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue];
++         _4 = const 4_usize;
++         _5 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff
index 0275d7e8a0d..a46daef435f 100644
--- a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff
@@ -6,7 +6,8 @@
       let _1: u32;
       let mut _2: [u32; 4];
       let _3: usize;
-      let mut _4: bool;
+      let mut _4: usize;
+      let mut _5: bool;
       scope 1 {
           debug x => _1;
       }
@@ -17,9 +18,11 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Lt(copy _3, const 4_usize);
--         assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind unreachable];
-+         _4 = const true;
+-         _4 = Len(_2);
+-         _5 = Lt(copy _3, copy _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable];
++         _4 = const 4_usize;
++         _5 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff
index 490ed4b55a1..1a4e15b45fa 100644
--- a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff
@@ -6,7 +6,8 @@
       let _1: u32;
       let mut _2: [u32; 4];
       let _3: usize;
-      let mut _4: bool;
+      let mut _4: usize;
+      let mut _5: bool;
       scope 1 {
           debug x => _1;
       }
@@ -17,9 +18,11 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Lt(copy _3, const 4_usize);
--         assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind continue];
-+         _4 = const true;
+-         _4 = Len(_2);
+-         _5 = Lt(copy _3, copy _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue];
++         _4 = const 4_usize;
++         _5 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/array_index.rs b/tests/mir-opt/dataflow-const-prop/array_index.rs
index 1aa8dcd28f4..e442ef99f79 100644
--- a/tests/mir-opt/dataflow-const-prop/array_index.rs
+++ b/tests/mir-opt/dataflow-const-prop/array_index.rs
@@ -11,10 +11,9 @@ fn main() {
 
     // CHECK:       [[array_lit]] = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
     // CHECK-NOT:   {{_.*}} = Len(
-    // CHECK-NOT:   {{_.*}} = PtrMetadata(
     // CHECK-NOT:   {{_.*}} = Lt(
     // CHECK-NOT:   assert(move _
-    // CHECK:       {{_.*}} = const 2_usize;
+    // CHECK:       {{_.*}} = const 4_usize;
     // CHECK:       {{_.*}} = const true;
     // CHECK:       assert(const true
     // CHECK:       [[x]] = copy [[array_lit]][2 of 3];
diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff
index f0d59ef5923..b7ff0b671f7 100644
--- a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff
@@ -6,7 +6,8 @@
       let _1: u8;
       let mut _2: [u8; 5000];
       let _3: usize;
-      let mut _4: bool;
+      let mut _4: usize;
+      let mut _5: bool;
       scope 1 {
           debug x => _1;
       }
@@ -17,9 +18,11 @@
           _2 = [const 0_u8; 5000];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Lt(copy _3, const 5000_usize);
--         assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind unreachable];
-+         _4 = const true;
+-         _4 = Len(_2);
+-         _5 = Lt(copy _3, copy _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable];
++         _4 = const 5000_usize;
++         _5 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff
index 959c3e75214..af6e3626142 100644
--- a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff
@@ -6,7 +6,8 @@
       let _1: u8;
       let mut _2: [u8; 5000];
       let _3: usize;
-      let mut _4: bool;
+      let mut _4: usize;
+      let mut _5: bool;
       scope 1 {
           debug x => _1;
       }
@@ -17,9 +18,11 @@
           _2 = [const 0_u8; 5000];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Lt(copy _3, const 5000_usize);
--         assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind continue];
-+         _4 = const true;
+-         _4 = Len(_2);
+-         _5 = Lt(copy _3, copy _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue];
++         _4 = const 5000_usize;
++         _5 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff
index f0d59ef5923..b7ff0b671f7 100644
--- a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff
@@ -6,7 +6,8 @@
       let _1: u8;
       let mut _2: [u8; 5000];
       let _3: usize;
-      let mut _4: bool;
+      let mut _4: usize;
+      let mut _5: bool;
       scope 1 {
           debug x => _1;
       }
@@ -17,9 +18,11 @@
           _2 = [const 0_u8; 5000];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Lt(copy _3, const 5000_usize);
--         assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind unreachable];
-+         _4 = const true;
+-         _4 = Len(_2);
+-         _5 = Lt(copy _3, copy _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable];
++         _4 = const 5000_usize;
++         _5 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff
index 959c3e75214..af6e3626142 100644
--- a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff
@@ -6,7 +6,8 @@
       let _1: u8;
       let mut _2: [u8; 5000];
       let _3: usize;
-      let mut _4: bool;
+      let mut _4: usize;
+      let mut _5: bool;
       scope 1 {
           debug x => _1;
       }
@@ -17,9 +18,11 @@
           _2 = [const 0_u8; 5000];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Lt(copy _3, const 5000_usize);
--         assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind continue];
-+         _4 = const true;
+-         _4 = Len(_2);
+-         _5 = Lt(copy _3, copy _4);
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue];
++         _4 = const 5000_usize;
++         _5 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.rs b/tests/mir-opt/dataflow-const-prop/large_array_index.rs
index e490cfde247..e9f2fa2badf 100644
--- a/tests/mir-opt/dataflow-const-prop/large_array_index.rs
+++ b/tests/mir-opt/dataflow-const-prop/large_array_index.rs
@@ -10,7 +10,7 @@ fn main() {
 
     // CHECK: debug x => [[x:_.*]];
     // CHECK: [[array_lit:_.*]] = [const 0_u8; 5000];
-    // CHECK: {{_.*}} = const 2_usize;
+    // CHECK: {{_.*}} = const 5000_usize;
     // CHECK: {{_.*}} = const true;
     // CHECK: assert(const true
     // CHECK: [[x]] = copy [[array_lit]][2 of 3];
diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff
index 618121ea632..dfa541b1200 100644
--- a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff
@@ -7,7 +7,8 @@
       let mut _2: u32;
       let mut _3: [u32; 8];
       let _4: usize;
-      let mut _5: bool;
+      let mut _5: usize;
+      let mut _6: bool;
       scope 1 {
           debug x => _1;
       }
@@ -19,9 +20,11 @@
           _3 = [const 42_u32; 8];
           StorageLive(_4);
           _4 = const 2_usize;
--         _5 = Lt(copy _4, const 8_usize);
--         assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind unreachable];
-+         _5 = const true;
+-         _5 = Len(_3);
+-         _6 = Lt(copy _4, copy _5);
+-         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind unreachable];
++         _5 = const 8_usize;
++         _6 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff
index 1788f58432b..9ede3c5f7ac 100644
--- a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff
@@ -7,7 +7,8 @@
       let mut _2: u32;
       let mut _3: [u32; 8];
       let _4: usize;
-      let mut _5: bool;
+      let mut _5: usize;
+      let mut _6: bool;
       scope 1 {
           debug x => _1;
       }
@@ -19,9 +20,11 @@
           _3 = [const 42_u32; 8];
           StorageLive(_4);
           _4 = const 2_usize;
--         _5 = Lt(copy _4, const 8_usize);
--         assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind continue];
-+         _5 = const true;
+-         _5 = Len(_3);
+-         _6 = Lt(copy _4, copy _5);
+-         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind continue];
++         _5 = const 8_usize;
++         _6 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff
index 618121ea632..dfa541b1200 100644
--- a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff
@@ -7,7 +7,8 @@
       let mut _2: u32;
       let mut _3: [u32; 8];
       let _4: usize;
-      let mut _5: bool;
+      let mut _5: usize;
+      let mut _6: bool;
       scope 1 {
           debug x => _1;
       }
@@ -19,9 +20,11 @@
           _3 = [const 42_u32; 8];
           StorageLive(_4);
           _4 = const 2_usize;
--         _5 = Lt(copy _4, const 8_usize);
--         assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind unreachable];
-+         _5 = const true;
+-         _5 = Len(_3);
+-         _6 = Lt(copy _4, copy _5);
+-         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind unreachable];
++         _5 = const 8_usize;
++         _6 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff
index 1788f58432b..9ede3c5f7ac 100644
--- a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff
@@ -7,7 +7,8 @@
       let mut _2: u32;
       let mut _3: [u32; 8];
       let _4: usize;
-      let mut _5: bool;
+      let mut _5: usize;
+      let mut _6: bool;
       scope 1 {
           debug x => _1;
       }
@@ -19,9 +20,11 @@
           _3 = [const 42_u32; 8];
           StorageLive(_4);
           _4 = const 2_usize;
--         _5 = Lt(copy _4, const 8_usize);
--         assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind continue];
-+         _5 = const true;
+-         _5 = Len(_3);
+-         _6 = Lt(copy _4, copy _5);
+-         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind continue];
++         _5 = const 8_usize;
++         _6 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/repeat.rs b/tests/mir-opt/dataflow-const-prop/repeat.rs
index 1bc2cb82a60..2067aa3d709 100644
--- a/tests/mir-opt/dataflow-const-prop/repeat.rs
+++ b/tests/mir-opt/dataflow-const-prop/repeat.rs
@@ -9,9 +9,8 @@ fn main() {
 
     // CHECK: [[array_lit:_.*]] = [const 42_u32; 8];
     // CHECK-NOT: {{_.*}} = Len(
-    // CHECK-NOT: {{_.*}} = PtrMetadata(
     // CHECK-NOT: {{_.*}} = Lt(
-    // CHECK: {{_.*}} = const 2_usize;
+    // CHECK: {{_.*}} = const 8_usize;
     // CHECK: {{_.*}} = const true;
     // CHECK: assert(const true
 
diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff
new file mode 100644
index 00000000000..e71992316dc
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff
@@ -0,0 +1,77 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let _1: u32;
+      let mut _2: &[u32];
+      let mut _3: &[u32; 3];
+      let _4: &[u32; 3];
+      let _5: [u32; 3];
+      let _6: usize;
+      let mut _7: usize;
+      let mut _8: bool;
+      let mut _10: &[u32];
+      let _11: usize;
+      let mut _12: usize;
+      let mut _13: bool;
+      let mut _14: &[u32; 3];
+      scope 1 {
+          debug local => _1;
+          let _9: u32;
+          scope 2 {
+              debug constant => _9;
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          _14 = const main::promoted[0];
+          _4 = copy _14;
+          _3 = copy _4;
+          _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast));
+          StorageDead(_3);
+          StorageLive(_6);
+          _6 = const 1_usize;
+-         _7 = Len((*_2));
+-         _8 = Lt(copy _6, copy _7);
+-         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable];
++         _7 = const 3_usize;
++         _8 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+-         _1 = copy (*_2)[_6];
++         _1 = copy (*_2)[1 of 2];
+          StorageDead(_6);
+          StorageDead(_4);
+          StorageDead(_2);
+          StorageLive(_9);
+          StorageLive(_10);
+          _10 = const main::SLICE;
+          StorageLive(_11);
+          _11 = const 1_usize;
+-         _12 = Len((*_10));
+-         _13 = Lt(copy _11, copy _12);
+-         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind unreachable];
++         _12 = const 3_usize;
++         _13 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind unreachable];
+      }
+  
+      bb2: {
+-         _9 = copy (*_10)[_11];
++         _9 = copy (*_10)[1 of 2];
+          StorageDead(_11);
+          StorageDead(_10);
+          _0 = const ();
+          StorageDead(_9);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff
new file mode 100644
index 00000000000..26de8595768
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff
@@ -0,0 +1,77 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let _1: u32;
+      let mut _2: &[u32];
+      let mut _3: &[u32; 3];
+      let _4: &[u32; 3];
+      let _5: [u32; 3];
+      let _6: usize;
+      let mut _7: usize;
+      let mut _8: bool;
+      let mut _10: &[u32];
+      let _11: usize;
+      let mut _12: usize;
+      let mut _13: bool;
+      let mut _14: &[u32; 3];
+      scope 1 {
+          debug local => _1;
+          let _9: u32;
+          scope 2 {
+              debug constant => _9;
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          _14 = const main::promoted[0];
+          _4 = copy _14;
+          _3 = copy _4;
+          _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast));
+          StorageDead(_3);
+          StorageLive(_6);
+          _6 = const 1_usize;
+-         _7 = Len((*_2));
+-         _8 = Lt(copy _6, copy _7);
+-         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue];
++         _7 = const 3_usize;
++         _8 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue];
+      }
+  
+      bb1: {
+-         _1 = copy (*_2)[_6];
++         _1 = copy (*_2)[1 of 2];
+          StorageDead(_6);
+          StorageDead(_4);
+          StorageDead(_2);
+          StorageLive(_9);
+          StorageLive(_10);
+          _10 = const main::SLICE;
+          StorageLive(_11);
+          _11 = const 1_usize;
+-         _12 = Len((*_10));
+-         _13 = Lt(copy _11, copy _12);
+-         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind continue];
++         _12 = const 3_usize;
++         _13 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind continue];
+      }
+  
+      bb2: {
+-         _9 = copy (*_10)[_11];
++         _9 = copy (*_10)[1 of 2];
+          StorageDead(_11);
+          StorageDead(_10);
+          _0 = const ();
+          StorageDead(_9);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff
new file mode 100644
index 00000000000..e71992316dc
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff
@@ -0,0 +1,77 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let _1: u32;
+      let mut _2: &[u32];
+      let mut _3: &[u32; 3];
+      let _4: &[u32; 3];
+      let _5: [u32; 3];
+      let _6: usize;
+      let mut _7: usize;
+      let mut _8: bool;
+      let mut _10: &[u32];
+      let _11: usize;
+      let mut _12: usize;
+      let mut _13: bool;
+      let mut _14: &[u32; 3];
+      scope 1 {
+          debug local => _1;
+          let _9: u32;
+          scope 2 {
+              debug constant => _9;
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          _14 = const main::promoted[0];
+          _4 = copy _14;
+          _3 = copy _4;
+          _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast));
+          StorageDead(_3);
+          StorageLive(_6);
+          _6 = const 1_usize;
+-         _7 = Len((*_2));
+-         _8 = Lt(copy _6, copy _7);
+-         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable];
++         _7 = const 3_usize;
++         _8 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+-         _1 = copy (*_2)[_6];
++         _1 = copy (*_2)[1 of 2];
+          StorageDead(_6);
+          StorageDead(_4);
+          StorageDead(_2);
+          StorageLive(_9);
+          StorageLive(_10);
+          _10 = const main::SLICE;
+          StorageLive(_11);
+          _11 = const 1_usize;
+-         _12 = Len((*_10));
+-         _13 = Lt(copy _11, copy _12);
+-         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind unreachable];
++         _12 = const 3_usize;
++         _13 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind unreachable];
+      }
+  
+      bb2: {
+-         _9 = copy (*_10)[_11];
++         _9 = copy (*_10)[1 of 2];
+          StorageDead(_11);
+          StorageDead(_10);
+          _0 = const ();
+          StorageDead(_9);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff
new file mode 100644
index 00000000000..26de8595768
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff
@@ -0,0 +1,77 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let _1: u32;
+      let mut _2: &[u32];
+      let mut _3: &[u32; 3];
+      let _4: &[u32; 3];
+      let _5: [u32; 3];
+      let _6: usize;
+      let mut _7: usize;
+      let mut _8: bool;
+      let mut _10: &[u32];
+      let _11: usize;
+      let mut _12: usize;
+      let mut _13: bool;
+      let mut _14: &[u32; 3];
+      scope 1 {
+          debug local => _1;
+          let _9: u32;
+          scope 2 {
+              debug constant => _9;
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          _14 = const main::promoted[0];
+          _4 = copy _14;
+          _3 = copy _4;
+          _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast));
+          StorageDead(_3);
+          StorageLive(_6);
+          _6 = const 1_usize;
+-         _7 = Len((*_2));
+-         _8 = Lt(copy _6, copy _7);
+-         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue];
++         _7 = const 3_usize;
++         _8 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue];
+      }
+  
+      bb1: {
+-         _1 = copy (*_2)[_6];
++         _1 = copy (*_2)[1 of 2];
+          StorageDead(_6);
+          StorageDead(_4);
+          StorageDead(_2);
+          StorageLive(_9);
+          StorageLive(_10);
+          _10 = const main::SLICE;
+          StorageLive(_11);
+          _11 = const 1_usize;
+-         _12 = Len((*_10));
+-         _13 = Lt(copy _11, copy _12);
+-         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind continue];
++         _12 = const 3_usize;
++         _13 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind continue];
+      }
+  
+      bb2: {
+-         _9 = copy (*_10)[_11];
++         _9 = copy (*_10)[1 of 2];
+          StorageDead(_11);
+          StorageDead(_10);
+          _0 = const ();
+          StorageDead(_9);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.rs b/tests/mir-opt/dataflow-const-prop/slice_len.rs
new file mode 100644
index 00000000000..e0e68f9fde5
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/slice_len.rs
@@ -0,0 +1,34 @@
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+//@ test-mir-pass: DataflowConstProp
+//@ compile-flags: -Zmir-enable-passes=+InstSimplify-after-simplifycfg
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
+// EMIT_MIR slice_len.main.DataflowConstProp.diff
+
+// CHECK-LABEL: fn main(
+fn main() {
+    // CHECK: debug local => [[local:_.*]];
+    // CHECK: debug constant => [[constant:_.*]];
+
+    // CHECK-NOT: {{_.*}} = Len(
+    // CHECK-NOT: {{_.*}} = Lt(
+    // CHECK-NOT: assert(move _
+    // CHECK: {{_.*}} = const 3_usize;
+    // CHECK: {{_.*}} = const true;
+    // CHECK: assert(const true,
+
+    // CHECK: [[local]] = copy (*{{_.*}})[1 of 2];
+    let local = (&[1u32, 2, 3] as &[u32])[1];
+
+    // CHECK-NOT: {{_.*}} = Len(
+    // CHECK-NOT: {{_.*}} = Lt(
+    // CHECK-NOT: assert(move _
+    const SLICE: &[u32] = &[1, 2, 3];
+    // CHECK: {{_.*}} = const 3_usize;
+    // CHECK: {{_.*}} = const true;
+    // CHECK: assert(const true,
+
+    // CHECK-NOT: [[constant]] = {{copy|move}} (*{{_.*}})[_
+    // CHECK: [[constant]] = copy (*{{_.*}})[1 of 2];
+    let constant = SLICE[1];
+}
diff --git a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff
index b4197c09ac9..60742ef0e9a 100644
--- a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff
+++ b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff
@@ -22,14 +22,14 @@
   
       bb1: {
           StorageDead(_3);
-          _4 = PtrMetadata(copy _2);
+          _4 = Len((*_2));
           _5 = const 4_usize;
           _6 = Ge(move _4, move _5);
           switchInt(move _6) -> [0: bb2, otherwise: bb3];
       }
   
       bb2: {
-          _7 = PtrMetadata(copy _2);
+          _7 = Len((*_2));
           _8 = const 3_usize;
           _9 = Ge(move _7, move _8);
 -         switchInt(move _9) -> [0: bb7, otherwise: bb8];
diff --git a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff
index 4bcb13ca49c..7337a32f525 100644
--- a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff
+++ b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff
@@ -22,14 +22,14 @@
   
       bb1: {
           StorageDead(_3);
-          _4 = PtrMetadata(copy _2);
+          _4 = Len((*_2));
           _5 = const 4_usize;
           _6 = Ge(move _4, move _5);
           switchInt(move _6) -> [0: bb2, otherwise: bb3];
       }
   
       bb2: {
-          _7 = PtrMetadata(copy _2);
+          _7 = Len((*_2));
           _8 = const 3_usize;
           _9 = Ge(move _7, move _8);
 -         switchInt(move _9) -> [0: bb7, otherwise: bb8];
diff --git a/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-abort.diff b/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-abort.diff
index 183b4d2599f..3f052ee19fd 100644
--- a/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-abort.diff
@@ -53,7 +53,7 @@
           StorageLive(_8);
 -         _8 = copy _2;
 +         _8 = const usize::MAX;
-          _9 = PtrMetadata(copy _1);
+          _9 = Len((*_1));
 -         _10 = Lt(copy _8, copy _9);
 -         assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb3, unwind unreachable];
 +         _10 = Lt(const usize::MAX, copy _9);
@@ -72,7 +72,7 @@
           StorageDead(_5);
           StorageLive(_11);
           _11 = const 0_usize;
-          _12 = PtrMetadata(copy _1);
+          _12 = Len((*_1));
 -         _13 = Lt(copy _11, copy _12);
 -         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb5, unwind unreachable];
 +         _13 = Lt(const 0_usize, copy _12);
diff --git a/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-unwind.diff b/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-unwind.diff
index 03e8aa3bd9b..84b738c7804 100644
--- a/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-unwind.diff
@@ -53,7 +53,7 @@
           StorageLive(_8);
 -         _8 = copy _2;
 +         _8 = const usize::MAX;
-          _9 = PtrMetadata(copy _1);
+          _9 = Len((*_1));
 -         _10 = Lt(copy _8, copy _9);
 -         assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb3, unwind continue];
 +         _10 = Lt(const usize::MAX, copy _9);
@@ -72,7 +72,7 @@
           StorageDead(_5);
           StorageLive(_11);
           _11 = const 0_usize;
-          _12 = PtrMetadata(copy _1);
+          _12 = Len((*_1));
 -         _13 = Lt(copy _11, copy _12);
 -         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb5, unwind continue];
 +         _13 = Lt(const 0_usize, copy _12);
diff --git a/tests/mir-opt/gvn.dedup_multiple_bounds_checks_lengths.GVN.panic-abort.diff b/tests/mir-opt/gvn.dedup_multiple_bounds_checks_lengths.GVN.panic-abort.diff
deleted file mode 100644
index 4b077f580f1..00000000000
--- a/tests/mir-opt/gvn.dedup_multiple_bounds_checks_lengths.GVN.panic-abort.diff
+++ /dev/null
@@ -1,72 +0,0 @@
-- // MIR for `dedup_multiple_bounds_checks_lengths` before GVN
-+ // MIR for `dedup_multiple_bounds_checks_lengths` after GVN
-  
-  fn dedup_multiple_bounds_checks_lengths(_1: &[i32]) -> [i32; 3] {
-      debug x => _1;
-      let mut _0: [i32; 3];
-      let mut _2: i32;
-      let _3: usize;
-      let mut _4: usize;
-      let mut _5: bool;
-      let mut _6: i32;
-      let _7: usize;
-      let mut _8: usize;
-      let mut _9: bool;
-      let mut _10: i32;
-      let _11: usize;
-      let mut _12: usize;
-      let mut _13: bool;
-  
-      bb0: {
-          StorageLive(_2);
-          StorageLive(_3);
-          _3 = const 42_usize;
-          _4 = PtrMetadata(copy _1);
--         _5 = Lt(copy _3, copy _4);
--         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable];
-+         _5 = Lt(const 42_usize, copy _4);
-+         assert(move _5, "index out of bounds: the length is {} but the index is {}", copy _4, const 42_usize) -> [success: bb1, unwind unreachable];
-      }
-  
-      bb1: {
--         _2 = copy (*_1)[_3];
-+         _2 = copy (*_1)[42 of 43];
-          StorageLive(_6);
-          StorageLive(_7);
-          _7 = const 13_usize;
--         _8 = PtrMetadata(copy _1);
--         _9 = Lt(copy _7, copy _8);
--         assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind unreachable];
-+         _8 = copy _4;
-+         _9 = Lt(const 13_usize, copy _4);
-+         assert(move _9, "index out of bounds: the length is {} but the index is {}", copy _4, const 13_usize) -> [success: bb2, unwind unreachable];
-      }
-  
-      bb2: {
--         _6 = copy (*_1)[_7];
-+         _6 = copy (*_1)[13 of 14];
-          StorageLive(_10);
-          StorageLive(_11);
-          _11 = const 7_usize;
--         _12 = PtrMetadata(copy _1);
--         _13 = Lt(copy _11, copy _12);
--         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb3, unwind unreachable];
-+         _12 = copy _4;
-+         _13 = Lt(const 7_usize, copy _4);
-+         assert(move _13, "index out of bounds: the length is {} but the index is {}", copy _4, const 7_usize) -> [success: bb3, unwind unreachable];
-      }
-  
-      bb3: {
--         _10 = copy (*_1)[_11];
-+         _10 = copy (*_1)[7 of 8];
-          _0 = [move _2, move _6, move _10];
-          StorageDead(_10);
-          StorageDead(_6);
-          StorageDead(_2);
-          StorageDead(_11);
-          StorageDead(_7);
-          StorageDead(_3);
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/gvn.dedup_multiple_bounds_checks_lengths.GVN.panic-unwind.diff b/tests/mir-opt/gvn.dedup_multiple_bounds_checks_lengths.GVN.panic-unwind.diff
deleted file mode 100644
index 87e69d44006..00000000000
--- a/tests/mir-opt/gvn.dedup_multiple_bounds_checks_lengths.GVN.panic-unwind.diff
+++ /dev/null
@@ -1,72 +0,0 @@
-- // MIR for `dedup_multiple_bounds_checks_lengths` before GVN
-+ // MIR for `dedup_multiple_bounds_checks_lengths` after GVN
-  
-  fn dedup_multiple_bounds_checks_lengths(_1: &[i32]) -> [i32; 3] {
-      debug x => _1;
-      let mut _0: [i32; 3];
-      let mut _2: i32;
-      let _3: usize;
-      let mut _4: usize;
-      let mut _5: bool;
-      let mut _6: i32;
-      let _7: usize;
-      let mut _8: usize;
-      let mut _9: bool;
-      let mut _10: i32;
-      let _11: usize;
-      let mut _12: usize;
-      let mut _13: bool;
-  
-      bb0: {
-          StorageLive(_2);
-          StorageLive(_3);
-          _3 = const 42_usize;
-          _4 = PtrMetadata(copy _1);
--         _5 = Lt(copy _3, copy _4);
--         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue];
-+         _5 = Lt(const 42_usize, copy _4);
-+         assert(move _5, "index out of bounds: the length is {} but the index is {}", copy _4, const 42_usize) -> [success: bb1, unwind continue];
-      }
-  
-      bb1: {
--         _2 = copy (*_1)[_3];
-+         _2 = copy (*_1)[42 of 43];
-          StorageLive(_6);
-          StorageLive(_7);
-          _7 = const 13_usize;
--         _8 = PtrMetadata(copy _1);
--         _9 = Lt(copy _7, copy _8);
--         assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind continue];
-+         _8 = copy _4;
-+         _9 = Lt(const 13_usize, copy _4);
-+         assert(move _9, "index out of bounds: the length is {} but the index is {}", copy _4, const 13_usize) -> [success: bb2, unwind continue];
-      }
-  
-      bb2: {
--         _6 = copy (*_1)[_7];
-+         _6 = copy (*_1)[13 of 14];
-          StorageLive(_10);
-          StorageLive(_11);
-          _11 = const 7_usize;
--         _12 = PtrMetadata(copy _1);
--         _13 = Lt(copy _11, copy _12);
--         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb3, unwind continue];
-+         _12 = copy _4;
-+         _13 = Lt(const 7_usize, copy _4);
-+         assert(move _13, "index out of bounds: the length is {} but the index is {}", copy _4, const 7_usize) -> [success: bb3, unwind continue];
-      }
-  
-      bb3: {
--         _10 = copy (*_1)[_11];
-+         _10 = copy (*_1)[7 of 8];
-          _0 = [move _2, move _6, move _10];
-          StorageDead(_10);
-          StorageDead(_6);
-          StorageDead(_2);
-          StorageDead(_11);
-          StorageDead(_7);
-          StorageDead(_3);
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff b/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff
index 7f44176b756..d4b22d05f6c 100644
--- a/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff
@@ -10,11 +10,13 @@
       let _5: ();
       let mut _6: T;
       let _7: usize;
-      let mut _8: bool;
-      let _9: ();
-      let mut _10: T;
-      let _11: usize;
-      let mut _12: bool;
+      let mut _8: usize;
+      let mut _9: bool;
+      let _10: ();
+      let mut _11: T;
+      let _12: usize;
+      let mut _13: usize;
+      let mut _14: bool;
       scope 1 {
           debug a => _3;
       }
@@ -30,10 +32,12 @@
           StorageLive(_6);
           StorageLive(_7);
           _7 = const 0_usize;
--         _8 = Lt(copy _7, const N);
--         assert(move _8, "index out of bounds: the length is {} but the index is {}", const N, copy _7) -> [success: bb1, unwind unreachable];
-+         _8 = Lt(const 0_usize, const N);
-+         assert(move _8, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind unreachable];
+-         _8 = Len(_3);
+-         _9 = Lt(copy _7, copy _8);
+-         assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb1, unwind unreachable];
++         _8 = const N;
++         _9 = Lt(const 0_usize, const N);
++         assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
@@ -47,27 +51,29 @@
           StorageDead(_6);
           StorageDead(_7);
           StorageDead(_5);
-          StorageLive(_9);
           StorageLive(_10);
           StorageLive(_11);
-          _11 = copy _2;
--         _12 = Lt(copy _11, const N);
--         assert(move _12, "index out of bounds: the length is {} but the index is {}", const N, copy _11) -> [success: bb3, unwind unreachable];
-+         _12 = Lt(copy _2, const N);
-+         assert(move _12, "index out of bounds: the length is {} but the index is {}", const N, copy _2) -> [success: bb3, unwind unreachable];
+          StorageLive(_12);
+          _12 = copy _2;
+-         _13 = Len(_3);
+-         _14 = Lt(copy _12, copy _13);
+-         assert(move _14, "index out of bounds: the length is {} but the index is {}", move _13, copy _12) -> [success: bb3, unwind unreachable];
++         _13 = const N;
++         _14 = Lt(copy _2, const N);
++         assert(move _14, "index out of bounds: the length is {} but the index is {}", const N, copy _2) -> [success: bb3, unwind unreachable];
       }
   
       bb3: {
--         _10 = copy _3[_11];
--         _9 = opaque::<T>(move _10) -> [return: bb4, unwind unreachable];
-+         _10 = copy _1;
-+         _9 = opaque::<T>(copy _1) -> [return: bb4, unwind unreachable];
+-         _11 = copy _3[_12];
+-         _10 = opaque::<T>(move _11) -> [return: bb4, unwind unreachable];
++         _11 = copy _1;
++         _10 = opaque::<T>(copy _1) -> [return: bb4, unwind unreachable];
       }
   
       bb4: {
-          StorageDead(_10);
           StorageDead(_11);
-          StorageDead(_9);
+          StorageDead(_12);
+          StorageDead(_10);
           _0 = const ();
           StorageDead(_3);
           return;
diff --git a/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff b/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff
index d34882d725f..708c0f92e54 100644
--- a/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff
@@ -10,11 +10,13 @@
       let _5: ();
       let mut _6: T;
       let _7: usize;
-      let mut _8: bool;
-      let _9: ();
-      let mut _10: T;
-      let _11: usize;
-      let mut _12: bool;
+      let mut _8: usize;
+      let mut _9: bool;
+      let _10: ();
+      let mut _11: T;
+      let _12: usize;
+      let mut _13: usize;
+      let mut _14: bool;
       scope 1 {
           debug a => _3;
       }
@@ -30,10 +32,12 @@
           StorageLive(_6);
           StorageLive(_7);
           _7 = const 0_usize;
--         _8 = Lt(copy _7, const N);
--         assert(move _8, "index out of bounds: the length is {} but the index is {}", const N, copy _7) -> [success: bb1, unwind continue];
-+         _8 = Lt(const 0_usize, const N);
-+         assert(move _8, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind continue];
+-         _8 = Len(_3);
+-         _9 = Lt(copy _7, copy _8);
+-         assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb1, unwind continue];
++         _8 = const N;
++         _9 = Lt(const 0_usize, const N);
++         assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
@@ -47,27 +51,29 @@
           StorageDead(_6);
           StorageDead(_7);
           StorageDead(_5);
-          StorageLive(_9);
           StorageLive(_10);
           StorageLive(_11);
-          _11 = copy _2;
--         _12 = Lt(copy _11, const N);
--         assert(move _12, "index out of bounds: the length is {} but the index is {}", const N, copy _11) -> [success: bb3, unwind continue];
-+         _12 = Lt(copy _2, const N);
-+         assert(move _12, "index out of bounds: the length is {} but the index is {}", const N, copy _2) -> [success: bb3, unwind continue];
+          StorageLive(_12);
+          _12 = copy _2;
+-         _13 = Len(_3);
+-         _14 = Lt(copy _12, copy _13);
+-         assert(move _14, "index out of bounds: the length is {} but the index is {}", move _13, copy _12) -> [success: bb3, unwind continue];
++         _13 = const N;
++         _14 = Lt(copy _2, const N);
++         assert(move _14, "index out of bounds: the length is {} but the index is {}", const N, copy _2) -> [success: bb3, unwind continue];
       }
   
       bb3: {
--         _10 = copy _3[_11];
--         _9 = opaque::<T>(move _10) -> [return: bb4, unwind continue];
-+         _10 = copy _1;
-+         _9 = opaque::<T>(copy _1) -> [return: bb4, unwind continue];
+-         _11 = copy _3[_12];
+-         _10 = opaque::<T>(move _11) -> [return: bb4, unwind continue];
++         _11 = copy _1;
++         _10 = opaque::<T>(copy _1) -> [return: bb4, unwind continue];
       }
   
       bb4: {
-          StorageDead(_10);
           StorageDead(_11);
-          StorageDead(_9);
+          StorageDead(_12);
+          StorageDead(_10);
           _0 = const ();
           StorageDead(_3);
           return;
diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs
index c895a579259..10d1ccfdece 100644
--- a/tests/mir-opt/gvn.rs
+++ b/tests/mir-opt/gvn.rs
@@ -835,25 +835,6 @@ fn array_len(x: &mut [i32; 42]) -> usize {
     std::intrinsics::ptr_metadata(x)
 }
 
-// Check that we only load the length once, rather than all 3 times.
-fn dedup_multiple_bounds_checks_lengths(x: &[i32]) -> [i32; 3] {
-    // CHECK-LABEL: fn dedup_multiple_bounds_checks_lengths
-    // CHECK: [[LEN:_.+]] = PtrMetadata(copy _1);
-    // CHECK: Lt(const 42_usize, copy [[LEN]]);
-    // CHECK: assert{{.+}}copy [[LEN]]
-    // CHECK: [[A:_.+]] = copy (*_1)[42 of 43];
-    // CHECK-NOT: PtrMetadata
-    // CHECK: Lt(const 13_usize, copy [[LEN]]);
-    // CHECK: assert{{.+}}copy [[LEN]]
-    // CHECK: [[B:_.+]] = copy (*_1)[13 of 14];
-    // CHECK-NOT: PtrMetadata
-    // CHECK: Lt(const 7_usize, copy [[LEN]]);
-    // CHECK: assert{{.+}}copy [[LEN]]
-    // CHECK: [[C:_.+]] = copy (*_1)[7 of 8];
-    // CHECK: _0 = [move [[A]], move [[B]], move [[C]]]
-    [x[42], x[13], x[7]]
-}
-
 #[custom_mir(dialect = "runtime")]
 fn generic_cast_metadata<T, A: ?Sized, B: ?Sized>(ps: *const [T], pa: *const A, pb: *const B) {
     // CHECK-LABEL: fn generic_cast_metadata
@@ -1128,7 +1109,6 @@ enum Never {}
 // EMIT_MIR gvn.casts_before_aggregate_raw_ptr.GVN.diff
 // EMIT_MIR gvn.manual_slice_mut_len.GVN.diff
 // EMIT_MIR gvn.array_len.GVN.diff
-// EMIT_MIR gvn.dedup_multiple_bounds_checks_lengths.GVN.diff
 // EMIT_MIR gvn.generic_cast_metadata.GVN.diff
 // EMIT_MIR gvn.cast_pointer_eq.GVN.diff
 // EMIT_MIR gvn.aggregate_struct_then_transmute.GVN.diff
diff --git a/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-abort.diff b/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-abort.diff
index 1b305e746f5..6b6152c1117 100644
--- a/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-abort.diff
@@ -10,60 +10,62 @@
       let mut _6: &i32;
       let _7: &i32;
       let _8: usize;
-      let mut _9: bool;
-      let mut _11: *const dyn std::marker::Send;
-      let _12: &dyn std::marker::Send;
-      let mut _13: &i32;
-      let _14: &i32;
-      let _15: usize;
-      let mut _16: bool;
-      let _17: ();
+      let mut _9: usize;
+      let mut _10: bool;
+      let mut _12: *const dyn std::marker::Send;
+      let _13: &dyn std::marker::Send;
+      let mut _14: &i32;
+      let _15: &i32;
+      let _16: usize;
+      let mut _17: usize;
       let mut _18: bool;
-      let mut _19: *const dyn std::marker::Send;
-      let mut _20: *const dyn std::marker::Send;
+      let _19: ();
+      let mut _20: bool;
       let mut _21: *const dyn std::marker::Send;
-      let _22: ();
-      let mut _23: bool;
-      let mut _24: *const dyn std::marker::Send;
-      let mut _25: *const dyn std::marker::Send;
+      let mut _22: *const dyn std::marker::Send;
+      let mut _23: *const dyn std::marker::Send;
+      let _24: ();
+      let mut _25: bool;
       let mut _26: *const dyn std::marker::Send;
-      let _27: ();
-      let mut _28: bool;
-      let mut _29: *const dyn std::marker::Send;
-      let mut _30: *const dyn std::marker::Send;
+      let mut _27: *const dyn std::marker::Send;
+      let mut _28: *const dyn std::marker::Send;
+      let _29: ();
+      let mut _30: bool;
       let mut _31: *const dyn std::marker::Send;
-      let _32: ();
-      let mut _33: bool;
-      let mut _34: *const dyn std::marker::Send;
-      let mut _35: *const dyn std::marker::Send;
+      let mut _32: *const dyn std::marker::Send;
+      let mut _33: *const dyn std::marker::Send;
+      let _34: ();
+      let mut _35: bool;
       let mut _36: *const dyn std::marker::Send;
-      let _37: ();
-      let mut _38: bool;
-      let mut _39: *const dyn std::marker::Send;
-      let mut _40: *const dyn std::marker::Send;
+      let mut _37: *const dyn std::marker::Send;
+      let mut _38: *const dyn std::marker::Send;
+      let _39: ();
+      let mut _40: bool;
       let mut _41: *const dyn std::marker::Send;
-      let _42: ();
-      let mut _43: bool;
-      let mut _44: *const dyn std::marker::Send;
-      let mut _45: *const dyn std::marker::Send;
+      let mut _42: *const dyn std::marker::Send;
+      let mut _43: *const dyn std::marker::Send;
+      let _44: ();
+      let mut _45: bool;
       let mut _46: *const dyn std::marker::Send;
-      let mut _47: &[i32; 2];
+      let mut _47: *const dyn std::marker::Send;
+      let mut _48: *const dyn std::marker::Send;
+      let mut _49: &[i32; 2];
       scope 1 {
           debug slice => _1;
           let _3: *const dyn std::marker::Send;
           scope 2 {
               debug a => _3;
-              let _10: *const dyn std::marker::Send;
+              let _11: *const dyn std::marker::Send;
               scope 3 {
-                  debug b => _10;
+                  debug b => _11;
               }
           }
       }
   
       bb0: {
           StorageLive(_1);
-          _47 = const wide_ptr_same_provenance::promoted[0];
-          _1 = &(*_47);
+          _49 = const wide_ptr_same_provenance::promoted[0];
+          _1 = &(*_49);
           StorageLive(_3);
 -         StorageLive(_4);
 +         nop;
@@ -72,9 +74,11 @@
           StorageLive(_7);
           StorageLive(_8);
           _8 = const 0_usize;
--         _9 = Lt(copy _8, const 2_usize);
--         assert(move _9, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _8) -> [success: bb1, unwind unreachable];
-+         _9 = const true;
+-         _9 = Len((*_1));
+-         _10 = Lt(copy _8, copy _9);
+-         assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb1, unwind unreachable];
++         _9 = const 2_usize;
++         _10 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 2_usize, const 0_usize) -> [success: bb1, unwind unreachable];
       }
   
@@ -91,168 +95,170 @@
 +         nop;
           StorageDead(_7);
           StorageDead(_5);
-          StorageLive(_10);
--         StorageLive(_11);
+          StorageLive(_11);
+-         StorageLive(_12);
 +         nop;
-          StorageLive(_12);
           StorageLive(_13);
           StorageLive(_14);
           StorageLive(_15);
-          _15 = const 1_usize;
--         _16 = Lt(copy _15, const 2_usize);
--         assert(move _16, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _15) -> [success: bb2, unwind unreachable];
-+         _16 = const true;
+          StorageLive(_16);
+          _16 = const 1_usize;
+-         _17 = Len((*_1));
+-         _18 = Lt(copy _16, copy _17);
+-         assert(move _18, "index out of bounds: the length is {} but the index is {}", move _17, copy _16) -> [success: bb2, unwind unreachable];
++         _17 = const 2_usize;
++         _18 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 2_usize, const 1_usize) -> [success: bb2, unwind unreachable];
       }
   
       bb2: {
--         _14 = &(*_1)[_15];
-+         _14 = &(*_1)[1 of 2];
-          _13 = &(*_14);
-          _12 = move _13 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast));
-          StorageDead(_13);
-          _11 = &raw const (*_12);
--         _10 = move _11 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
--         StorageDead(_11);
-+         _10 = copy _11;
-+         nop;
+-         _15 = &(*_1)[_16];
++         _15 = &(*_1)[1 of 2];
+          _14 = &(*_15);
+          _13 = move _14 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast));
           StorageDead(_14);
-          StorageDead(_12);
-          StorageLive(_17);
-          StorageLive(_18);
+          _12 = &raw const (*_13);
+-         _11 = move _12 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+-         StorageDead(_12);
++         _11 = copy _12;
++         nop;
+          StorageDead(_15);
+          StorageDead(_13);
           StorageLive(_19);
--         _19 = copy _3;
-+         _19 = copy _4;
           StorageLive(_20);
           StorageLive(_21);
--         _21 = copy _10;
--         _20 = move _21 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
-+         _21 = copy _11;
-+         _20 = copy _11;
+-         _21 = copy _3;
++         _21 = copy _4;
+          StorageLive(_22);
+          StorageLive(_23);
+-         _23 = copy _11;
+-         _22 = move _23 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
++         _23 = copy _12;
++         _22 = copy _12;
+          StorageDead(_23);
+-         _20 = Eq(move _21, move _22);
++         _20 = Eq(copy _4, copy _12);
+          StorageDead(_22);
           StorageDead(_21);
--         _18 = Eq(move _19, move _20);
-+         _18 = Eq(copy _4, copy _11);
-          StorageDead(_20);
-          StorageDead(_19);
-          _17 = opaque::<bool>(move _18) -> [return: bb3, unwind unreachable];
+          _19 = opaque::<bool>(move _20) -> [return: bb3, unwind unreachable];
       }
   
       bb3: {
-          StorageDead(_18);
-          StorageDead(_17);
-          StorageLive(_22);
-          StorageLive(_23);
+          StorageDead(_20);
+          StorageDead(_19);
           StorageLive(_24);
--         _24 = copy _3;
-+         _24 = copy _4;
           StorageLive(_25);
           StorageLive(_26);
--         _26 = copy _10;
--         _25 = move _26 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
-+         _26 = copy _11;
-+         _25 = copy _11;
+-         _26 = copy _3;
++         _26 = copy _4;
+          StorageLive(_27);
+          StorageLive(_28);
+-         _28 = copy _11;
+-         _27 = move _28 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
++         _28 = copy _12;
++         _27 = copy _12;
+          StorageDead(_28);
+-         _25 = Ne(move _26, move _27);
++         _25 = Ne(copy _4, copy _12);
+          StorageDead(_27);
           StorageDead(_26);
--         _23 = Ne(move _24, move _25);
-+         _23 = Ne(copy _4, copy _11);
-          StorageDead(_25);
-          StorageDead(_24);
-          _22 = opaque::<bool>(move _23) -> [return: bb4, unwind unreachable];
+          _24 = opaque::<bool>(move _25) -> [return: bb4, unwind unreachable];
       }
   
       bb4: {
-          StorageDead(_23);
-          StorageDead(_22);
-          StorageLive(_27);
-          StorageLive(_28);
+          StorageDead(_25);
+          StorageDead(_24);
           StorageLive(_29);
--         _29 = copy _3;
-+         _29 = copy _4;
           StorageLive(_30);
           StorageLive(_31);
--         _31 = copy _10;
--         _30 = move _31 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
-+         _31 = copy _11;
-+         _30 = copy _11;
+-         _31 = copy _3;
++         _31 = copy _4;
+          StorageLive(_32);
+          StorageLive(_33);
+-         _33 = copy _11;
+-         _32 = move _33 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
++         _33 = copy _12;
++         _32 = copy _12;
+          StorageDead(_33);
+-         _30 = Lt(move _31, move _32);
++         _30 = Lt(copy _4, copy _12);
+          StorageDead(_32);
           StorageDead(_31);
--         _28 = Lt(move _29, move _30);
-+         _28 = Lt(copy _4, copy _11);
-          StorageDead(_30);
-          StorageDead(_29);
-          _27 = opaque::<bool>(move _28) -> [return: bb5, unwind unreachable];
+          _29 = opaque::<bool>(move _30) -> [return: bb5, unwind unreachable];
       }
   
       bb5: {
-          StorageDead(_28);
-          StorageDead(_27);
-          StorageLive(_32);
-          StorageLive(_33);
+          StorageDead(_30);
+          StorageDead(_29);
           StorageLive(_34);
--         _34 = copy _3;
-+         _34 = copy _4;
           StorageLive(_35);
           StorageLive(_36);
--         _36 = copy _10;
--         _35 = move _36 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
-+         _36 = copy _11;
-+         _35 = copy _11;
+-         _36 = copy _3;
++         _36 = copy _4;
+          StorageLive(_37);
+          StorageLive(_38);
+-         _38 = copy _11;
+-         _37 = move _38 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
++         _38 = copy _12;
++         _37 = copy _12;
+          StorageDead(_38);
+-         _35 = Le(move _36, move _37);
++         _35 = Le(copy _4, copy _12);
+          StorageDead(_37);
           StorageDead(_36);
--         _33 = Le(move _34, move _35);
-+         _33 = Le(copy _4, copy _11);
-          StorageDead(_35);
-          StorageDead(_34);
-          _32 = opaque::<bool>(move _33) -> [return: bb6, unwind unreachable];
+          _34 = opaque::<bool>(move _35) -> [return: bb6, unwind unreachable];
       }
   
       bb6: {
-          StorageDead(_33);
-          StorageDead(_32);
-          StorageLive(_37);
-          StorageLive(_38);
+          StorageDead(_35);
+          StorageDead(_34);
           StorageLive(_39);
--         _39 = copy _3;
-+         _39 = copy _4;
           StorageLive(_40);
           StorageLive(_41);
--         _41 = copy _10;
--         _40 = move _41 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
-+         _41 = copy _11;
-+         _40 = copy _11;
+-         _41 = copy _3;
++         _41 = copy _4;
+          StorageLive(_42);
+          StorageLive(_43);
+-         _43 = copy _11;
+-         _42 = move _43 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
++         _43 = copy _12;
++         _42 = copy _12;
+          StorageDead(_43);
+-         _40 = Gt(move _41, move _42);
++         _40 = Gt(copy _4, copy _12);
+          StorageDead(_42);
           StorageDead(_41);
--         _38 = Gt(move _39, move _40);
-+         _38 = Gt(copy _4, copy _11);
-          StorageDead(_40);
-          StorageDead(_39);
-          _37 = opaque::<bool>(move _38) -> [return: bb7, unwind unreachable];
+          _39 = opaque::<bool>(move _40) -> [return: bb7, unwind unreachable];
       }
   
       bb7: {
-          StorageDead(_38);
-          StorageDead(_37);
-          StorageLive(_42);
-          StorageLive(_43);
+          StorageDead(_40);
+          StorageDead(_39);
           StorageLive(_44);
--         _44 = copy _3;
-+         _44 = copy _4;
           StorageLive(_45);
           StorageLive(_46);
--         _46 = copy _10;
--         _45 = move _46 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
-+         _46 = copy _11;
-+         _45 = copy _11;
+-         _46 = copy _3;
++         _46 = copy _4;
+          StorageLive(_47);
+          StorageLive(_48);
+-         _48 = copy _11;
+-         _47 = move _48 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
++         _48 = copy _12;
++         _47 = copy _12;
+          StorageDead(_48);
+-         _45 = Ge(move _46, move _47);
++         _45 = Ge(copy _4, copy _12);
+          StorageDead(_47);
           StorageDead(_46);
--         _43 = Ge(move _44, move _45);
-+         _43 = Ge(copy _4, copy _11);
-          StorageDead(_45);
-          StorageDead(_44);
-          _42 = opaque::<bool>(move _43) -> [return: bb8, unwind unreachable];
+          _44 = opaque::<bool>(move _45) -> [return: bb8, unwind unreachable];
       }
   
       bb8: {
-          StorageDead(_43);
-          StorageDead(_42);
+          StorageDead(_45);
+          StorageDead(_44);
           _0 = const ();
-          StorageDead(_15);
-          StorageDead(_10);
+          StorageDead(_16);
+          StorageDead(_11);
           StorageDead(_8);
           StorageDead(_3);
           StorageDead(_1);
diff --git a/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-unwind.diff b/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-unwind.diff
index e418ecf25bd..093c1ec6ce3 100644
--- a/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-unwind.diff
@@ -10,60 +10,62 @@
       let mut _6: &i32;
       let _7: &i32;
       let _8: usize;
-      let mut _9: bool;
-      let mut _11: *const dyn std::marker::Send;
-      let _12: &dyn std::marker::Send;
-      let mut _13: &i32;
-      let _14: &i32;
-      let _15: usize;
-      let mut _16: bool;
-      let _17: ();
+      let mut _9: usize;
+      let mut _10: bool;
+      let mut _12: *const dyn std::marker::Send;
+      let _13: &dyn std::marker::Send;
+      let mut _14: &i32;
+      let _15: &i32;
+      let _16: usize;
+      let mut _17: usize;
       let mut _18: bool;
-      let mut _19: *const dyn std::marker::Send;
-      let mut _20: *const dyn std::marker::Send;
+      let _19: ();
+      let mut _20: bool;
       let mut _21: *const dyn std::marker::Send;
-      let _22: ();
-      let mut _23: bool;
-      let mut _24: *const dyn std::marker::Send;
-      let mut _25: *const dyn std::marker::Send;
+      let mut _22: *const dyn std::marker::Send;
+      let mut _23: *const dyn std::marker::Send;
+      let _24: ();
+      let mut _25: bool;
       let mut _26: *const dyn std::marker::Send;
-      let _27: ();
-      let mut _28: bool;
-      let mut _29: *const dyn std::marker::Send;
-      let mut _30: *const dyn std::marker::Send;
+      let mut _27: *const dyn std::marker::Send;
+      let mut _28: *const dyn std::marker::Send;
+      let _29: ();
+      let mut _30: bool;
       let mut _31: *const dyn std::marker::Send;
-      let _32: ();
-      let mut _33: bool;
-      let mut _34: *const dyn std::marker::Send;
-      let mut _35: *const dyn std::marker::Send;
+      let mut _32: *const dyn std::marker::Send;
+      let mut _33: *const dyn std::marker::Send;
+      let _34: ();
+      let mut _35: bool;
       let mut _36: *const dyn std::marker::Send;
-      let _37: ();
-      let mut _38: bool;
-      let mut _39: *const dyn std::marker::Send;
-      let mut _40: *const dyn std::marker::Send;
+      let mut _37: *const dyn std::marker::Send;
+      let mut _38: *const dyn std::marker::Send;
+      let _39: ();
+      let mut _40: bool;
       let mut _41: *const dyn std::marker::Send;
-      let _42: ();
-      let mut _43: bool;
-      let mut _44: *const dyn std::marker::Send;
-      let mut _45: *const dyn std::marker::Send;
+      let mut _42: *const dyn std::marker::Send;
+      let mut _43: *const dyn std::marker::Send;
+      let _44: ();
+      let mut _45: bool;
       let mut _46: *const dyn std::marker::Send;
-      let mut _47: &[i32; 2];
+      let mut _47: *const dyn std::marker::Send;
+      let mut _48: *const dyn std::marker::Send;
+      let mut _49: &[i32; 2];
       scope 1 {
           debug slice => _1;
           let _3: *const dyn std::marker::Send;
           scope 2 {
               debug a => _3;
-              let _10: *const dyn std::marker::Send;
+              let _11: *const dyn std::marker::Send;
               scope 3 {
-                  debug b => _10;
+                  debug b => _11;
               }
           }
       }
   
       bb0: {
           StorageLive(_1);
-          _47 = const wide_ptr_same_provenance::promoted[0];
-          _1 = &(*_47);
+          _49 = const wide_ptr_same_provenance::promoted[0];
+          _1 = &(*_49);
           StorageLive(_3);
 -         StorageLive(_4);
 +         nop;
@@ -72,9 +74,11 @@
           StorageLive(_7);
           StorageLive(_8);
           _8 = const 0_usize;
--         _9 = Lt(copy _8, const 2_usize);
--         assert(move _9, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _8) -> [success: bb1, unwind continue];
-+         _9 = const true;
+-         _9 = Len((*_1));
+-         _10 = Lt(copy _8, copy _9);
+-         assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb1, unwind continue];
++         _9 = const 2_usize;
++         _10 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 2_usize, const 0_usize) -> [success: bb1, unwind continue];
       }
   
@@ -91,168 +95,170 @@
 +         nop;
           StorageDead(_7);
           StorageDead(_5);
-          StorageLive(_10);
--         StorageLive(_11);
+          StorageLive(_11);
+-         StorageLive(_12);
 +         nop;
-          StorageLive(_12);
           StorageLive(_13);
           StorageLive(_14);
           StorageLive(_15);
-          _15 = const 1_usize;
--         _16 = Lt(copy _15, const 2_usize);
--         assert(move _16, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _15) -> [success: bb2, unwind continue];
-+         _16 = const true;
+          StorageLive(_16);
+          _16 = const 1_usize;
+-         _17 = Len((*_1));
+-         _18 = Lt(copy _16, copy _17);
+-         assert(move _18, "index out of bounds: the length is {} but the index is {}", move _17, copy _16) -> [success: bb2, unwind continue];
++         _17 = const 2_usize;
++         _18 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 2_usize, const 1_usize) -> [success: bb2, unwind continue];
       }
   
       bb2: {
--         _14 = &(*_1)[_15];
-+         _14 = &(*_1)[1 of 2];
-          _13 = &(*_14);
-          _12 = move _13 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast));
-          StorageDead(_13);
-          _11 = &raw const (*_12);
--         _10 = move _11 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
--         StorageDead(_11);
-+         _10 = copy _11;
-+         nop;
+-         _15 = &(*_1)[_16];
++         _15 = &(*_1)[1 of 2];
+          _14 = &(*_15);
+          _13 = move _14 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast));
           StorageDead(_14);
-          StorageDead(_12);
-          StorageLive(_17);
-          StorageLive(_18);
+          _12 = &raw const (*_13);
+-         _11 = move _12 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+-         StorageDead(_12);
++         _11 = copy _12;
++         nop;
+          StorageDead(_15);
+          StorageDead(_13);
           StorageLive(_19);
--         _19 = copy _3;
-+         _19 = copy _4;
           StorageLive(_20);
           StorageLive(_21);
--         _21 = copy _10;
--         _20 = move _21 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
-+         _21 = copy _11;
-+         _20 = copy _11;
+-         _21 = copy _3;
++         _21 = copy _4;
+          StorageLive(_22);
+          StorageLive(_23);
+-         _23 = copy _11;
+-         _22 = move _23 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
++         _23 = copy _12;
++         _22 = copy _12;
+          StorageDead(_23);
+-         _20 = Eq(move _21, move _22);
++         _20 = Eq(copy _4, copy _12);
+          StorageDead(_22);
           StorageDead(_21);
--         _18 = Eq(move _19, move _20);
-+         _18 = Eq(copy _4, copy _11);
-          StorageDead(_20);
-          StorageDead(_19);
-          _17 = opaque::<bool>(move _18) -> [return: bb3, unwind continue];
+          _19 = opaque::<bool>(move _20) -> [return: bb3, unwind continue];
       }
   
       bb3: {
-          StorageDead(_18);
-          StorageDead(_17);
-          StorageLive(_22);
-          StorageLive(_23);
+          StorageDead(_20);
+          StorageDead(_19);
           StorageLive(_24);
--         _24 = copy _3;
-+         _24 = copy _4;
           StorageLive(_25);
           StorageLive(_26);
--         _26 = copy _10;
--         _25 = move _26 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
-+         _26 = copy _11;
-+         _25 = copy _11;
+-         _26 = copy _3;
++         _26 = copy _4;
+          StorageLive(_27);
+          StorageLive(_28);
+-         _28 = copy _11;
+-         _27 = move _28 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
++         _28 = copy _12;
++         _27 = copy _12;
+          StorageDead(_28);
+-         _25 = Ne(move _26, move _27);
++         _25 = Ne(copy _4, copy _12);
+          StorageDead(_27);
           StorageDead(_26);
--         _23 = Ne(move _24, move _25);
-+         _23 = Ne(copy _4, copy _11);
-          StorageDead(_25);
-          StorageDead(_24);
-          _22 = opaque::<bool>(move _23) -> [return: bb4, unwind continue];
+          _24 = opaque::<bool>(move _25) -> [return: bb4, unwind continue];
       }
   
       bb4: {
-          StorageDead(_23);
-          StorageDead(_22);
-          StorageLive(_27);
-          StorageLive(_28);
+          StorageDead(_25);
+          StorageDead(_24);
           StorageLive(_29);
--         _29 = copy _3;
-+         _29 = copy _4;
           StorageLive(_30);
           StorageLive(_31);
--         _31 = copy _10;
--         _30 = move _31 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
-+         _31 = copy _11;
-+         _30 = copy _11;
+-         _31 = copy _3;
++         _31 = copy _4;
+          StorageLive(_32);
+          StorageLive(_33);
+-         _33 = copy _11;
+-         _32 = move _33 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
++         _33 = copy _12;
++         _32 = copy _12;
+          StorageDead(_33);
+-         _30 = Lt(move _31, move _32);
++         _30 = Lt(copy _4, copy _12);
+          StorageDead(_32);
           StorageDead(_31);
--         _28 = Lt(move _29, move _30);
-+         _28 = Lt(copy _4, copy _11);
-          StorageDead(_30);
-          StorageDead(_29);
-          _27 = opaque::<bool>(move _28) -> [return: bb5, unwind continue];
+          _29 = opaque::<bool>(move _30) -> [return: bb5, unwind continue];
       }
   
       bb5: {
-          StorageDead(_28);
-          StorageDead(_27);
-          StorageLive(_32);
-          StorageLive(_33);
+          StorageDead(_30);
+          StorageDead(_29);
           StorageLive(_34);
--         _34 = copy _3;
-+         _34 = copy _4;
           StorageLive(_35);
           StorageLive(_36);
--         _36 = copy _10;
--         _35 = move _36 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
-+         _36 = copy _11;
-+         _35 = copy _11;
+-         _36 = copy _3;
++         _36 = copy _4;
+          StorageLive(_37);
+          StorageLive(_38);
+-         _38 = copy _11;
+-         _37 = move _38 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
++         _38 = copy _12;
++         _37 = copy _12;
+          StorageDead(_38);
+-         _35 = Le(move _36, move _37);
++         _35 = Le(copy _4, copy _12);
+          StorageDead(_37);
           StorageDead(_36);
--         _33 = Le(move _34, move _35);
-+         _33 = Le(copy _4, copy _11);
-          StorageDead(_35);
-          StorageDead(_34);
-          _32 = opaque::<bool>(move _33) -> [return: bb6, unwind continue];
+          _34 = opaque::<bool>(move _35) -> [return: bb6, unwind continue];
       }
   
       bb6: {
-          StorageDead(_33);
-          StorageDead(_32);
-          StorageLive(_37);
-          StorageLive(_38);
+          StorageDead(_35);
+          StorageDead(_34);
           StorageLive(_39);
--         _39 = copy _3;
-+         _39 = copy _4;
           StorageLive(_40);
           StorageLive(_41);
--         _41 = copy _10;
--         _40 = move _41 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
-+         _41 = copy _11;
-+         _40 = copy _11;
+-         _41 = copy _3;
++         _41 = copy _4;
+          StorageLive(_42);
+          StorageLive(_43);
+-         _43 = copy _11;
+-         _42 = move _43 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
++         _43 = copy _12;
++         _42 = copy _12;
+          StorageDead(_43);
+-         _40 = Gt(move _41, move _42);
++         _40 = Gt(copy _4, copy _12);
+          StorageDead(_42);
           StorageDead(_41);
--         _38 = Gt(move _39, move _40);
-+         _38 = Gt(copy _4, copy _11);
-          StorageDead(_40);
-          StorageDead(_39);
-          _37 = opaque::<bool>(move _38) -> [return: bb7, unwind continue];
+          _39 = opaque::<bool>(move _40) -> [return: bb7, unwind continue];
       }
   
       bb7: {
-          StorageDead(_38);
-          StorageDead(_37);
-          StorageLive(_42);
-          StorageLive(_43);
+          StorageDead(_40);
+          StorageDead(_39);
           StorageLive(_44);
--         _44 = copy _3;
-+         _44 = copy _4;
           StorageLive(_45);
           StorageLive(_46);
--         _46 = copy _10;
--         _45 = move _46 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
-+         _46 = copy _11;
-+         _45 = copy _11;
+-         _46 = copy _3;
++         _46 = copy _4;
+          StorageLive(_47);
+          StorageLive(_48);
+-         _48 = copy _11;
+-         _47 = move _48 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
++         _48 = copy _12;
++         _47 = copy _12;
+          StorageDead(_48);
+-         _45 = Ge(move _46, move _47);
++         _45 = Ge(copy _4, copy _12);
+          StorageDead(_47);
           StorageDead(_46);
--         _43 = Ge(move _44, move _45);
-+         _43 = Ge(copy _4, copy _11);
-          StorageDead(_45);
-          StorageDead(_44);
-          _42 = opaque::<bool>(move _43) -> [return: bb8, unwind continue];
+          _44 = opaque::<bool>(move _45) -> [return: bb8, unwind continue];
       }
   
       bb8: {
-          StorageDead(_43);
-          StorageDead(_42);
+          StorageDead(_45);
+          StorageDead(_44);
           _0 = const ();
-          StorageDead(_15);
-          StorageDead(_10);
+          StorageDead(_16);
+          StorageDead(_11);
           StorageDead(_8);
           StorageDead(_3);
           StorageDead(_1);
diff --git a/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-abort.diff b/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-abort.diff
new file mode 100644
index 00000000000..f39df7ffca0
--- /dev/null
+++ b/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-abort.diff
@@ -0,0 +1,77 @@
+- // MIR for `norm2` before InstSimplify-after-simplifycfg
++ // MIR for `norm2` after InstSimplify-after-simplifycfg
+  
+  fn norm2(_1: [f32; 2]) -> f32 {
+      debug x => _1;
+      let mut _0: f32;
+      let _2: f32;
+      let _3: usize;
+      let mut _4: usize;
+      let mut _5: bool;
+      let _7: usize;
+      let mut _8: usize;
+      let mut _9: bool;
+      let mut _10: f32;
+      let mut _11: f32;
+      let mut _12: f32;
+      let mut _13: f32;
+      let mut _14: f32;
+      let mut _15: f32;
+      scope 1 {
+          debug a => _2;
+          let _6: f32;
+          scope 2 {
+              debug b => _6;
+          }
+      }
+  
+      bb0: {
+          StorageLive(_2);
+          StorageLive(_3);
+          _3 = const 0_usize;
+-         _4 = Len(_1);
++         _4 = const 2_usize;
+          _5 = Lt(copy _3, copy _4);
+          assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+          _2 = copy _1[_3];
+          StorageDead(_3);
+          StorageLive(_6);
+          StorageLive(_7);
+          _7 = const 1_usize;
+-         _8 = Len(_1);
++         _8 = const 2_usize;
+          _9 = Lt(copy _7, copy _8);
+          assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind unreachable];
+      }
+  
+      bb2: {
+          _6 = copy _1[_7];
+          StorageDead(_7);
+          StorageLive(_10);
+          StorageLive(_11);
+          _11 = copy _2;
+          StorageLive(_12);
+          _12 = copy _2;
+          _10 = Mul(move _11, move _12);
+          StorageDead(_12);
+          StorageDead(_11);
+          StorageLive(_13);
+          StorageLive(_14);
+          _14 = copy _6;
+          StorageLive(_15);
+          _15 = copy _6;
+          _13 = Mul(move _14, move _15);
+          StorageDead(_15);
+          StorageDead(_14);
+          _0 = Add(move _10, move _13);
+          StorageDead(_13);
+          StorageDead(_10);
+          StorageDead(_6);
+          StorageDead(_2);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-unwind.diff b/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-unwind.diff
new file mode 100644
index 00000000000..0e7d5653c68
--- /dev/null
+++ b/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-unwind.diff
@@ -0,0 +1,77 @@
+- // MIR for `norm2` before InstSimplify-after-simplifycfg
++ // MIR for `norm2` after InstSimplify-after-simplifycfg
+  
+  fn norm2(_1: [f32; 2]) -> f32 {
+      debug x => _1;
+      let mut _0: f32;
+      let _2: f32;
+      let _3: usize;
+      let mut _4: usize;
+      let mut _5: bool;
+      let _7: usize;
+      let mut _8: usize;
+      let mut _9: bool;
+      let mut _10: f32;
+      let mut _11: f32;
+      let mut _12: f32;
+      let mut _13: f32;
+      let mut _14: f32;
+      let mut _15: f32;
+      scope 1 {
+          debug a => _2;
+          let _6: f32;
+          scope 2 {
+              debug b => _6;
+          }
+      }
+  
+      bb0: {
+          StorageLive(_2);
+          StorageLive(_3);
+          _3 = const 0_usize;
+-         _4 = Len(_1);
++         _4 = const 2_usize;
+          _5 = Lt(copy _3, copy _4);
+          assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue];
+      }
+  
+      bb1: {
+          _2 = copy _1[_3];
+          StorageDead(_3);
+          StorageLive(_6);
+          StorageLive(_7);
+          _7 = const 1_usize;
+-         _8 = Len(_1);
++         _8 = const 2_usize;
+          _9 = Lt(copy _7, copy _8);
+          assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind continue];
+      }
+  
+      bb2: {
+          _6 = copy _1[_7];
+          StorageDead(_7);
+          StorageLive(_10);
+          StorageLive(_11);
+          _11 = copy _2;
+          StorageLive(_12);
+          _12 = copy _2;
+          _10 = Mul(move _11, move _12);
+          StorageDead(_12);
+          StorageDead(_11);
+          StorageLive(_13);
+          StorageLive(_14);
+          _14 = copy _6;
+          StorageLive(_15);
+          _15 = copy _6;
+          _13 = Mul(move _14, move _15);
+          StorageDead(_15);
+          StorageDead(_14);
+          _0 = Add(move _10, move _13);
+          StorageDead(_13);
+          StorageDead(_10);
+          StorageDead(_6);
+          StorageDead(_2);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/instsimplify/combine_array_len.rs b/tests/mir-opt/instsimplify/combine_array_len.rs
new file mode 100644
index 00000000000..91f43f75689
--- /dev/null
+++ b/tests/mir-opt/instsimplify/combine_array_len.rs
@@ -0,0 +1,15 @@
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+//@ test-mir-pass: InstSimplify-after-simplifycfg
+
+// EMIT_MIR combine_array_len.norm2.InstSimplify-after-simplifycfg.diff
+fn norm2(x: [f32; 2]) -> f32 {
+    // CHECK-LABEL: fn norm2(
+    // CHECK-NOT: Len(
+    let a = x[0];
+    let b = x[1];
+    a * a + b * b
+}
+
+fn main() {
+    assert_eq!(norm2([3.0, 4.0]), 5.0 * 5.0);
+}
diff --git a/tests/mir-opt/issue_72181.foo.built.after.mir b/tests/mir-opt/issue_72181.foo.built.after.mir
index 7593b795432..314cf8b367f 100644
--- a/tests/mir-opt/issue_72181.foo.built.after.mir
+++ b/tests/mir-opt/issue_72181.foo.built.after.mir
@@ -4,14 +4,15 @@ fn foo(_1: [(Never, u32); 1]) -> u32 {
     debug xs => _1;
     let mut _0: u32;
     let _2: usize;
-    let mut _3: bool;
+    let mut _3: usize;
+    let mut _4: bool;
 
     bb0: {
         StorageLive(_2);
         _2 = const 0_usize;
-        FakeRead(ForIndex, _1);
-        _3 = Lt(copy _2, const 1_usize);
-        assert(move _3, "index out of bounds: the length is {} but the index is {}", const 1_usize, copy _2) -> [success: bb1, unwind: bb2];
+        _3 = Len(_1);
+        _4 = Lt(copy _2, copy _3);
+        assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, copy _2) -> [success: bb1, unwind: bb2];
     }
 
     bb1: {
diff --git a/tests/mir-opt/issue_72181.main.built.after.mir b/tests/mir-opt/issue_72181.main.built.after.mir
index 9f3803f5407..aade84a6dd2 100644
--- a/tests/mir-opt/issue_72181.main.built.after.mir
+++ b/tests/mir-opt/issue_72181.main.built.after.mir
@@ -7,7 +7,8 @@ fn main() -> () {
     let mut _4: Foo;
     let mut _5: u64;
     let _6: usize;
-    let mut _7: bool;
+    let mut _7: usize;
+    let mut _8: bool;
     scope 1 {
         let _2: [Foo; 2];
         scope 2 {
@@ -37,9 +38,9 @@ fn main() -> () {
         StorageLive(_5);
         StorageLive(_6);
         _6 = const 0_usize;
-        FakeRead(ForIndex, _2);
-        _7 = Lt(copy _6, const 2_usize);
-        assert(move _7, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _6) -> [success: bb3, unwind: bb5];
+        _7 = Len(_2);
+        _8 = Lt(copy _6, copy _7);
+        assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb3, unwind: bb5];
     }
 
     bb2: {
diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff
index 94ba7082c66..c02bab3524b 100644
--- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff
+++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff
@@ -7,16 +7,18 @@
       let _2: &[T];
       let _3: &[T; 3];
       let _4: [T; 3];
-      let mut _8: !;
+      let mut _5: usize;
+      let mut _6: bool;
+      let mut _10: !;
       scope 1 {
           debug v => _2;
-          let _5: &T;
-          let _6: &T;
           let _7: &T;
+          let _8: &T;
+          let _9: &T;
           scope 2 {
-              debug v1 => _5;
-              debug v2 => _6;
-              debug v3 => _7;
+              debug v1 => _7;
+              debug v2 => _8;
+              debug v3 => _9;
           }
       }
   
@@ -25,23 +27,25 @@
           _4 = [copy _1, copy _1, copy _1];
           _3 = &_4;
           _2 = copy _3 as &[T] (PointerCoercion(Unsize, Implicit));
+          nop;
+          nop;
           goto -> bb2;
       }
   
       bb1: {
-          _8 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind unreachable;
+          _10 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind unreachable;
       }
   
       bb2: {
-          StorageLive(_5);
-          _5 = &(*_2)[0 of 3];
-          StorageLive(_6);
-          _6 = &(*_2)[1 of 3];
           StorageLive(_7);
-          _7 = &(*_2)[2 of 3];
+          _7 = &(*_2)[0 of 3];
+          StorageLive(_8);
+          _8 = &(*_2)[1 of 3];
+          StorageLive(_9);
+          _9 = &(*_2)[2 of 3];
+          StorageDead(_9);
+          StorageDead(_8);
           StorageDead(_7);
-          StorageDead(_6);
-          StorageDead(_5);
           StorageDead(_4);
           return;
       }
diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff
index 0455b2c326e..49be042588c 100644
--- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff
+++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff
@@ -7,16 +7,18 @@
       let _2: &[T];
       let _3: &[T; 3];
       let _4: [T; 3];
-      let mut _8: !;
+      let mut _5: usize;
+      let mut _6: bool;
+      let mut _10: !;
       scope 1 {
           debug v => _2;
-          let _5: &T;
-          let _6: &T;
           let _7: &T;
+          let _8: &T;
+          let _9: &T;
           scope 2 {
-              debug v1 => _5;
-              debug v2 => _6;
-              debug v3 => _7;
+              debug v1 => _7;
+              debug v2 => _8;
+              debug v3 => _9;
           }
       }
   
@@ -25,23 +27,25 @@
           _4 = [copy _1, copy _1, copy _1];
           _3 = &_4;
           _2 = copy _3 as &[T] (PointerCoercion(Unsize, Implicit));
+          nop;
+          nop;
           goto -> bb2;
       }
   
       bb1: {
-          _8 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind continue;
+          _10 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind continue;
       }
   
       bb2: {
-          StorageLive(_5);
-          _5 = &(*_2)[0 of 3];
-          StorageLive(_6);
-          _6 = &(*_2)[1 of 3];
           StorageLive(_7);
-          _7 = &(*_2)[2 of 3];
+          _7 = &(*_2)[0 of 3];
+          StorageLive(_8);
+          _8 = &(*_2)[1 of 3];
+          StorageLive(_9);
+          _9 = &(*_2)[2 of 3];
+          StorageDead(_9);
+          StorageDead(_8);
           StorageDead(_7);
-          StorageDead(_6);
-          StorageDead(_5);
           StorageDead(_4);
           return;
       }
diff --git a/tests/mir-opt/issue_91633.foo.built.after.mir b/tests/mir-opt/issue_91633.foo.built.after.mir
index bf65b5b4a8c..50fdf08375a 100644
--- a/tests/mir-opt/issue_91633.foo.built.after.mir
+++ b/tests/mir-opt/issue_91633.foo.built.after.mir
@@ -6,9 +6,8 @@ fn foo(_1: Box<[T]>) -> T {
     let _2: T;
     let mut _3: &T;
     let _4: usize;
-    let mut _5: *const [T];
-    let mut _6: usize;
-    let mut _7: bool;
+    let mut _5: usize;
+    let mut _6: bool;
     scope 1 {
         debug f => _2;
     }
@@ -18,10 +17,9 @@ fn foo(_1: Box<[T]>) -> T {
         StorageLive(_3);
         StorageLive(_4);
         _4 = const 0_usize;
-        _5 = &raw const (*_1);
-        _6 = PtrMetadata(move _5);
-        _7 = Lt(copy _4, copy _6);
-        assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _4) -> [success: bb1, unwind: bb5];
+        _5 = Len((*_1));
+        _6 = Lt(copy _4, copy _5);
+        assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind: bb5];
     }
 
     bb1: {
diff --git a/tests/mir-opt/issue_91633.fun.built.after.mir b/tests/mir-opt/issue_91633.fun.built.after.mir
index d2fc438d3e8..5b41b376719 100644
--- a/tests/mir-opt/issue_91633.fun.built.after.mir
+++ b/tests/mir-opt/issue_91633.fun.built.after.mir
@@ -15,7 +15,7 @@ fn fun(_1: &[T]) -> &T {
         StorageLive(_2);
         StorageLive(_3);
         _3 = const 0_usize;
-        _4 = PtrMetadata(copy _1);
+        _4 = Len((*_1));
         _5 = Lt(copy _3, copy _4);
         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind: bb2];
     }
diff --git a/tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff
index 98c5e868046..f052c8f63dc 100644
--- a/tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff
+++ b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff
@@ -11,14 +11,16 @@
       let mut _6: &[u8];
       let mut _7: &[u8; N];
       let _8: usize;
-      let mut _9: bool;
+      let mut _9: usize;
+      let mut _10: bool;
   
       bb0: {
 -         StorageLive(_3);
 +         nop;
           StorageLive(_4);
           _4 = copy _1;
-          StorageLive(_5);
+-         StorageLive(_5);
++         nop;
           StorageLive(_6);
           StorageLive(_7);
           _7 = &(*_2);
@@ -38,13 +40,16 @@
       }
   
       bb2: {
-          StorageDead(_5);
+-         StorageDead(_5);
++         nop;
           StorageDead(_4);
           StorageLive(_8);
           _8 = copy _1;
--         _9 = Lt(copy _8, const N);
--         assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, copy _8) -> [success: bb3, unwind unreachable];
-+         _9 = copy _3;
+-         _9 = Len((*_2));
+-         _10 = Lt(copy _8, copy _9);
+-         assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb3, unwind unreachable];
++         _9 = const N;
++         _10 = copy _3;
 +         assert(copy _3, "index out of bounds: the length is {} but the index is {}", const N, copy _1) -> [success: bb3, unwind unreachable];
       }
   
@@ -56,7 +61,8 @@
       }
   
       bb4: {
-          StorageDead(_5);
+-         StorageDead(_5);
++         nop;
           StorageDead(_4);
           _0 = const 42_u8;
           goto -> bb5;
diff --git a/tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff
index 72c73137869..3299e300431 100644
--- a/tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff
+++ b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff
@@ -11,14 +11,16 @@
       let mut _6: &[u8];
       let mut _7: &[u8; N];
       let _8: usize;
-      let mut _9: bool;
+      let mut _9: usize;
+      let mut _10: bool;
   
       bb0: {
 -         StorageLive(_3);
 +         nop;
           StorageLive(_4);
           _4 = copy _1;
-          StorageLive(_5);
+-         StorageLive(_5);
++         nop;
           StorageLive(_6);
           StorageLive(_7);
           _7 = &(*_2);
@@ -38,13 +40,16 @@
       }
   
       bb2: {
-          StorageDead(_5);
+-         StorageDead(_5);
++         nop;
           StorageDead(_4);
           StorageLive(_8);
           _8 = copy _1;
--         _9 = Lt(copy _8, const N);
--         assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, copy _8) -> [success: bb3, unwind continue];
-+         _9 = copy _3;
+-         _9 = Len((*_2));
+-         _10 = Lt(copy _8, copy _9);
+-         assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb3, unwind continue];
++         _9 = const N;
++         _10 = copy _3;
 +         assert(copy _3, "index out of bounds: the length is {} but the index is {}", const N, copy _1) -> [success: bb3, unwind continue];
       }
   
@@ -56,7 +61,8 @@
       }
   
       bb4: {
-          StorageDead(_5);
+-         StorageDead(_5);
++         nop;
           StorageDead(_4);
           _0 = const 42_u8;
           goto -> bb5;
diff --git a/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff
index 9ffaf44c02b..329eb80b3c4 100644
--- a/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff
+++ b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff
@@ -11,16 +11,19 @@
       let mut _6: &[u8];
       let mut _7: &[u8; N];
       let _8: usize;
-      let mut _9: bool;
-      let _10: usize;
-      let mut _11: bool;
+      let mut _9: usize;
+      let mut _10: bool;
+      let _11: usize;
+      let mut _12: usize;
+      let mut _13: bool;
   
       bb0: {
 -         StorageLive(_3);
 +         nop;
           StorageLive(_4);
           _4 = copy _1;
-          StorageLive(_5);
+-         StorageLive(_5);
++         nop;
           StorageLive(_6);
           StorageLive(_7);
           _7 = &(*_2);
@@ -40,13 +43,16 @@
       }
   
       bb2: {
-          StorageDead(_5);
+-         StorageDead(_5);
++         nop;
           StorageDead(_4);
           StorageLive(_8);
           _8 = copy _1;
--         _9 = Lt(copy _8, const N);
--         assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, copy _8) -> [success: bb3, unwind unreachable];
-+         _9 = copy _3;
+-         _9 = Len((*_2));
+-         _10 = Lt(copy _8, copy _9);
+-         assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb3, unwind unreachable];
++         _9 = const N;
++         _10 = copy _3;
 +         assert(copy _3, "index out of bounds: the length is {} but the index is {}", const N, copy _1) -> [success: bb3, unwind unreachable];
       }
   
@@ -58,20 +64,23 @@
       }
   
       bb4: {
-          StorageDead(_5);
+-         StorageDead(_5);
++         nop;
           StorageDead(_4);
-          StorageLive(_10);
-          _10 = const 0_usize;
--         _11 = Lt(copy _10, const N);
--         assert(move _11, "index out of bounds: the length is {} but the index is {}", const N, copy _10) -> [success: bb5, unwind unreachable];
-+         _11 = Lt(const 0_usize, const N);
-+         assert(move _11, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb5, unwind unreachable];
+          StorageLive(_11);
+          _11 = const 0_usize;
+-         _12 = Len((*_2));
+-         _13 = Lt(copy _11, copy _12);
+-         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb5, unwind unreachable];
++         _12 = const N;
++         _13 = Lt(const 0_usize, const N);
++         assert(move _13, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb5, unwind unreachable];
       }
   
       bb5: {
--         (*_2)[_10] = const 42_u8;
+-         (*_2)[_11] = const 42_u8;
 +         (*_2)[0 of 1] = const 42_u8;
-          StorageDead(_10);
+          StorageDead(_11);
           _0 = const 42_u8;
           goto -> bb6;
       }
diff --git a/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff
index 08008e46335..ab007e133ec 100644
--- a/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff
+++ b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff
@@ -11,16 +11,19 @@
       let mut _6: &[u8];
       let mut _7: &[u8; N];
       let _8: usize;
-      let mut _9: bool;
-      let _10: usize;
-      let mut _11: bool;
+      let mut _9: usize;
+      let mut _10: bool;
+      let _11: usize;
+      let mut _12: usize;
+      let mut _13: bool;
   
       bb0: {
 -         StorageLive(_3);
 +         nop;
           StorageLive(_4);
           _4 = copy _1;
-          StorageLive(_5);
+-         StorageLive(_5);
++         nop;
           StorageLive(_6);
           StorageLive(_7);
           _7 = &(*_2);
@@ -40,13 +43,16 @@
       }
   
       bb2: {
-          StorageDead(_5);
+-         StorageDead(_5);
++         nop;
           StorageDead(_4);
           StorageLive(_8);
           _8 = copy _1;
--         _9 = Lt(copy _8, const N);
--         assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, copy _8) -> [success: bb3, unwind continue];
-+         _9 = copy _3;
+-         _9 = Len((*_2));
+-         _10 = Lt(copy _8, copy _9);
+-         assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb3, unwind continue];
++         _9 = const N;
++         _10 = copy _3;
 +         assert(copy _3, "index out of bounds: the length is {} but the index is {}", const N, copy _1) -> [success: bb3, unwind continue];
       }
   
@@ -58,20 +64,23 @@
       }
   
       bb4: {
-          StorageDead(_5);
+-         StorageDead(_5);
++         nop;
           StorageDead(_4);
-          StorageLive(_10);
-          _10 = const 0_usize;
--         _11 = Lt(copy _10, const N);
--         assert(move _11, "index out of bounds: the length is {} but the index is {}", const N, copy _10) -> [success: bb5, unwind continue];
-+         _11 = Lt(const 0_usize, const N);
-+         assert(move _11, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb5, unwind continue];
+          StorageLive(_11);
+          _11 = const 0_usize;
+-         _12 = Len((*_2));
+-         _13 = Lt(copy _11, copy _12);
+-         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb5, unwind continue];
++         _12 = const N;
++         _13 = Lt(const 0_usize, const N);
++         assert(move _13, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb5, unwind continue];
       }
   
       bb5: {
--         (*_2)[_10] = const 42_u8;
+-         (*_2)[_11] = const 42_u8;
 +         (*_2)[0 of 1] = const 42_u8;
-          StorageDead(_10);
+          StorageDead(_11);
           _0 = const 42_u8;
           goto -> bb6;
       }
diff --git a/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-abort.diff b/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-abort.diff
index 4b39e18d16c..20001f1248e 100644
--- a/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-abort.diff
+++ b/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-abort.diff
@@ -36,7 +36,7 @@
           StorageDead(_4);
           StorageLive(_7);
           _7 = copy _1;
-          _8 = PtrMetadata(copy _2);
+          _8 = Len((*_2));
           _9 = Lt(copy _7, copy _8);
           assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb3, unwind unreachable];
       }
diff --git a/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-unwind.diff b/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-unwind.diff
index f0d4afa21ae..ca8f92df5de 100644
--- a/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-unwind.diff
+++ b/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-unwind.diff
@@ -36,7 +36,7 @@
           StorageDead(_4);
           StorageLive(_7);
           _7 = copy _1;
-          _8 = PtrMetadata(copy _2);
+          _8 = Len((*_2));
           _9 = Lt(copy _7, copy _8);
           assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb3, unwind continue];
       }
diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
index 35e44b2314a..7294302609a 100644
--- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
+++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
@@ -27,19 +27,20 @@ fn main() -> () {
     let mut _0: ();
     let mut _1: [usize; ValTree(Leaf(0x00000003): usize)];
     let _3: usize;
-    let mut _4: bool;
-    let mut _6: bool;
-    let _7: bool;
-    let mut _8: usize;
-    let _9: bool;
+    let mut _4: usize;
+    let mut _5: bool;
+    let mut _7: bool;
+    let _8: bool;
+    let mut _9: usize;
+    let _10: bool;
     scope 1 {
         debug v => _1;
         let _2: &'?3 usize;
         scope 2 {
             debug p => _2;
-            let _5: &'?4 usize;
+            let _6: &'?4 usize;
             scope 3 {
-                debug q => _5;
+                debug q => _6;
             }
         }
     }
@@ -51,50 +52,50 @@ fn main() -> () {
         StorageLive(_2);
         StorageLive(_3);
         _3 = const ConstValue(Scalar(0x00000000): usize);
-        FakeRead(ForIndex, _1);
-        _4 = Lt(copy _3, const ConstValue(Scalar(0x00000003): usize));
-        assert(move _4, "index out of bounds: the length is {} but the index is {}", const ConstValue(Scalar(0x00000003): usize), copy _3) -> [success: bb1, unwind: bb7];
+        _4 = Len(_1);
+        _5 = Lt(copy _3, copy _4);
+        assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind: bb7];
     }
 
     bb1: {
         _2 = &'?2 _1[_3];
         FakeRead(ForLet(None), _2);
-        StorageLive(_5);
-        _5 = copy _2;
-        FakeRead(ForLet(None), _5);
         StorageLive(_6);
-        _6 = const ConstValue(Scalar(0x01): bool);
-        switchInt(move _6) -> [0: bb4, otherwise: bb2];
+        _6 = copy _2;
+        FakeRead(ForLet(None), _6);
+        StorageLive(_7);
+        _7 = const ConstValue(Scalar(0x01): bool);
+        switchInt(move _7) -> [0: bb4, otherwise: bb2];
     }
 
     bb2: {
-        StorageLive(_7);
         StorageLive(_8);
-        _8 = copy (*_5);
-        _7 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _8) -> [return: bb3, unwind: bb7];
+        StorageLive(_9);
+        _9 = copy (*_6);
+        _8 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7];
     }
 
     bb3: {
+        StorageDead(_9);
         StorageDead(_8);
-        StorageDead(_7);
         _0 = const ConstValue(ZeroSized: ());
         goto -> bb6;
     }
 
     bb4: {
-        StorageLive(_9);
-        _9 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x00000016): usize)) -> [return: bb5, unwind: bb7];
+        StorageLive(_10);
+        _10 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x00000016): usize)) -> [return: bb5, unwind: bb7];
     }
 
     bb5: {
-        StorageDead(_9);
+        StorageDead(_10);
         _0 = const ConstValue(ZeroSized: ());
         goto -> bb6;
     }
 
     bb6: {
+        StorageDead(_7);
         StorageDead(_6);
-        StorageDead(_5);
         StorageDead(_3);
         StorageDead(_2);
         StorageDead(_1);
diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
index 6d415f42d06..85b89a013c4 100644
--- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
+++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
@@ -27,19 +27,20 @@ fn main() -> () {
     let mut _0: ();
     let mut _1: [usize; ValTree(Leaf(0x0000000000000003): usize)];
     let _3: usize;
-    let mut _4: bool;
-    let mut _6: bool;
-    let _7: bool;
-    let mut _8: usize;
-    let _9: bool;
+    let mut _4: usize;
+    let mut _5: bool;
+    let mut _7: bool;
+    let _8: bool;
+    let mut _9: usize;
+    let _10: bool;
     scope 1 {
         debug v => _1;
         let _2: &'?3 usize;
         scope 2 {
             debug p => _2;
-            let _5: &'?4 usize;
+            let _6: &'?4 usize;
             scope 3 {
-                debug q => _5;
+                debug q => _6;
             }
         }
     }
@@ -51,50 +52,50 @@ fn main() -> () {
         StorageLive(_2);
         StorageLive(_3);
         _3 = const ConstValue(Scalar(0x0000000000000000): usize);
-        FakeRead(ForIndex, _1);
-        _4 = Lt(copy _3, const ConstValue(Scalar(0x0000000000000003): usize));
-        assert(move _4, "index out of bounds: the length is {} but the index is {}", const ConstValue(Scalar(0x0000000000000003): usize), copy _3) -> [success: bb1, unwind: bb7];
+        _4 = Len(_1);
+        _5 = Lt(copy _3, copy _4);
+        assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind: bb7];
     }
 
     bb1: {
         _2 = &'?2 _1[_3];
         FakeRead(ForLet(None), _2);
-        StorageLive(_5);
-        _5 = copy _2;
-        FakeRead(ForLet(None), _5);
         StorageLive(_6);
-        _6 = const ConstValue(Scalar(0x01): bool);
-        switchInt(move _6) -> [0: bb4, otherwise: bb2];
+        _6 = copy _2;
+        FakeRead(ForLet(None), _6);
+        StorageLive(_7);
+        _7 = const ConstValue(Scalar(0x01): bool);
+        switchInt(move _7) -> [0: bb4, otherwise: bb2];
     }
 
     bb2: {
-        StorageLive(_7);
         StorageLive(_8);
-        _8 = copy (*_5);
-        _7 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _8) -> [return: bb3, unwind: bb7];
+        StorageLive(_9);
+        _9 = copy (*_6);
+        _8 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7];
     }
 
     bb3: {
+        StorageDead(_9);
         StorageDead(_8);
-        StorageDead(_7);
         _0 = const ConstValue(ZeroSized: ());
         goto -> bb6;
     }
 
     bb4: {
-        StorageLive(_9);
-        _9 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x0000000000000016): usize)) -> [return: bb5, unwind: bb7];
+        StorageLive(_10);
+        _10 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x0000000000000016): usize)) -> [return: bb5, unwind: bb7];
     }
 
     bb5: {
-        StorageDead(_9);
+        StorageDead(_10);
         _0 = const ConstValue(ZeroSized: ());
         goto -> bb6;
     }
 
     bb6: {
+        StorageDead(_7);
         StorageDead(_6);
-        StorageDead(_5);
         StorageDead(_3);
         StorageDead(_2);
         StorageDead(_1);
diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir
index cff5b4c7243..1a1c8b4b942 100644
--- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir
@@ -13,7 +13,7 @@ fn step_forward(_1: u16, _2: usize) -> u16 {
                 scope 6 (inlined core::num::<impl u16>::checked_add) {
                     let mut _5: (u16, bool);
                     let mut _6: bool;
-                    scope 7 (inlined unlikely) {
+                    scope 7 (inlined std::intrinsics::unlikely) {
                         let _7: ();
                     }
                 }
@@ -55,7 +55,7 @@ fn step_forward(_1: u16, _2: usize) -> u16 {
     }
 
     bb3: {
-        _7 = cold_path() -> [return: bb4, unwind unreachable];
+        _7 = std::intrinsics::cold_path() -> [return: bb4, unwind unreachable];
     }
 
     bb4: {
diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir
index 6e0242a220d..e7e19af048a 100644
--- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir
@@ -13,7 +13,7 @@ fn step_forward(_1: u16, _2: usize) -> u16 {
                 scope 6 (inlined core::num::<impl u16>::checked_add) {
                     let mut _5: (u16, bool);
                     let mut _6: bool;
-                    scope 7 (inlined unlikely) {
+                    scope 7 (inlined std::intrinsics::unlikely) {
                         let _7: ();
                     }
                 }
@@ -55,7 +55,7 @@ fn step_forward(_1: u16, _2: usize) -> u16 {
     }
 
     bb3: {
-        _7 = cold_path() -> [return: bb4, unwind unreachable];
+        _7 = std::intrinsics::cold_path() -> [return: bb4, unwind unreachable];
     }
 
     bb4: {
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff
index 5b39e45806e..6575610727b 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff
@@ -7,16 +7,17 @@
       let mut _2: (i32, bool);
       let mut _4: [i32; 6];
       let _5: usize;
-      let mut _6: bool;
-      let mut _8: u32;
+      let mut _6: usize;
+      let mut _7: bool;
+      let mut _9: u32;
       scope 1 {
           debug x => _1;
           let _3: i32;
           scope 2 {
               debug y => _3;
-              let _7: u32;
+              let _8: u32;
               scope 3 {
-                  debug z => _7;
+                  debug z => _8;
               }
           }
       }
@@ -37,9 +38,10 @@
           _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32];
           StorageLive(_5);
           _5 = const 3_usize;
--         _6 = Lt(copy _5, const 6_usize);
--         assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind unreachable];
-+         _6 = const true;
+          _6 = const 6_usize;
+-         _7 = Lt(copy _5, copy _6);
+-         assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind unreachable];
++         _7 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> [success: bb2, unwind unreachable];
       }
   
@@ -48,13 +50,13 @@
 +         _3 = const 3_i32;
           StorageDead(_5);
           StorageDead(_4);
-          StorageLive(_7);
           StorageLive(_8);
-          _8 = const 42_u32;
--         _7 = copy _8;
-+         _7 = const 42_u32;
+          StorageLive(_9);
+          _9 = const 42_u32;
+-         _8 = copy _9;
++         _8 = const 42_u32;
+          StorageDead(_9);
           StorageDead(_8);
-          StorageDead(_7);
           StorageDead(_3);
           StorageDead(_1);
           return;
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff
index ea2742a6471..1a4ed5767fe 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff
@@ -7,16 +7,17 @@
       let mut _2: (i32, bool);
       let mut _4: [i32; 6];
       let _5: usize;
-      let mut _6: bool;
-      let mut _8: u32;
+      let mut _6: usize;
+      let mut _7: bool;
+      let mut _9: u32;
       scope 1 {
           debug x => _1;
           let _3: i32;
           scope 2 {
               debug y => _3;
-              let _7: u32;
+              let _8: u32;
               scope 3 {
-                  debug z => _7;
+                  debug z => _8;
               }
           }
       }
@@ -37,9 +38,10 @@
           _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32];
           StorageLive(_5);
           _5 = const 3_usize;
--         _6 = Lt(copy _5, const 6_usize);
--         assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind continue];
-+         _6 = const true;
+          _6 = const 6_usize;
+-         _7 = Lt(copy _5, copy _6);
+-         assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind continue];
++         _7 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> [success: bb2, unwind continue];
       }
   
@@ -48,13 +50,13 @@
 +         _3 = const 3_i32;
           StorageDead(_5);
           StorageDead(_4);
-          StorageLive(_7);
           StorageLive(_8);
-          _8 = const 42_u32;
--         _7 = copy _8;
-+         _7 = const 42_u32;
+          StorageLive(_9);
+          _9 = const 42_u32;
+-         _8 = copy _9;
++         _8 = const 42_u32;
+          StorageDead(_9);
           StorageDead(_8);
-          StorageDead(_7);
           StorageDead(_3);
           StorageDead(_1);
           return;
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff
index 5b39e45806e..6575610727b 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff
@@ -7,16 +7,17 @@
       let mut _2: (i32, bool);
       let mut _4: [i32; 6];
       let _5: usize;
-      let mut _6: bool;
-      let mut _8: u32;
+      let mut _6: usize;
+      let mut _7: bool;
+      let mut _9: u32;
       scope 1 {
           debug x => _1;
           let _3: i32;
           scope 2 {
               debug y => _3;
-              let _7: u32;
+              let _8: u32;
               scope 3 {
-                  debug z => _7;
+                  debug z => _8;
               }
           }
       }
@@ -37,9 +38,10 @@
           _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32];
           StorageLive(_5);
           _5 = const 3_usize;
--         _6 = Lt(copy _5, const 6_usize);
--         assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind unreachable];
-+         _6 = const true;
+          _6 = const 6_usize;
+-         _7 = Lt(copy _5, copy _6);
+-         assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind unreachable];
++         _7 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> [success: bb2, unwind unreachable];
       }
   
@@ -48,13 +50,13 @@
 +         _3 = const 3_i32;
           StorageDead(_5);
           StorageDead(_4);
-          StorageLive(_7);
           StorageLive(_8);
-          _8 = const 42_u32;
--         _7 = copy _8;
-+         _7 = const 42_u32;
+          StorageLive(_9);
+          _9 = const 42_u32;
+-         _8 = copy _9;
++         _8 = const 42_u32;
+          StorageDead(_9);
           StorageDead(_8);
-          StorageDead(_7);
           StorageDead(_3);
           StorageDead(_1);
           return;
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff
index ea2742a6471..1a4ed5767fe 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff
@@ -7,16 +7,17 @@
       let mut _2: (i32, bool);
       let mut _4: [i32; 6];
       let _5: usize;
-      let mut _6: bool;
-      let mut _8: u32;
+      let mut _6: usize;
+      let mut _7: bool;
+      let mut _9: u32;
       scope 1 {
           debug x => _1;
           let _3: i32;
           scope 2 {
               debug y => _3;
-              let _7: u32;
+              let _8: u32;
               scope 3 {
-                  debug z => _7;
+                  debug z => _8;
               }
           }
       }
@@ -37,9 +38,10 @@
           _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32];
           StorageLive(_5);
           _5 = const 3_usize;
--         _6 = Lt(copy _5, const 6_usize);
--         assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind continue];
-+         _6 = const true;
+          _6 = const 6_usize;
+-         _7 = Lt(copy _5, copy _6);
+-         assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind continue];
++         _7 = const true;
 +         assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> [success: bb2, unwind continue];
       }
   
@@ -48,13 +50,13 @@
 +         _3 = const 3_i32;
           StorageDead(_5);
           StorageDead(_4);
-          StorageLive(_7);
           StorageLive(_8);
-          _8 = const 42_u32;
--         _7 = copy _8;
-+         _7 = const 42_u32;
+          StorageLive(_9);
+          _9 = const 42_u32;
+-         _8 = copy _9;
++         _8 = const 42_u32;
+          StorageDead(_9);
           StorageDead(_8);
-          StorageDead(_7);
           StorageDead(_3);
           StorageDead(_1);
           return;
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-abort.diff
index f7fe08831b9..e2420a341e0 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-abort.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-abort.diff
@@ -7,18 +7,19 @@
       let mut _2: (i32, bool);
       let mut _4: [i32; 6];
       let _5: usize;
-      let mut _6: bool;
-      let mut _8: Point;
-+     let mut _9: u32;
+      let mut _6: usize;
+      let mut _7: bool;
+      let mut _9: Point;
 +     let mut _10: u32;
++     let mut _11: u32;
       scope 1 {
           debug x => _1;
           let _3: i32;
           scope 2 {
               debug y => _3;
-              let _7: u32;
+              let _8: u32;
               scope 3 {
-                  debug z => _7;
+                  debug z => _8;
               }
           }
       }
@@ -36,30 +37,31 @@
           _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32];
           StorageLive(_5);
           _5 = const 3_usize;
-          _6 = Lt(copy _5, const 6_usize);
-          assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind unreachable];
+          _6 = const 6_usize;
+          _7 = Lt(copy _5, copy _6);
+          assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind unreachable];
       }
   
       bb2: {
           _3 = copy _4[_5];
           StorageDead(_5);
           StorageDead(_4);
-          StorageLive(_7);
--         StorageLive(_8);
--         _8 = Point { x: const 12_u32, y: const 42_u32 };
--         _7 = copy (_8.1: u32);
--         StorageDead(_8);
-+         StorageLive(_9);
+          StorageLive(_8);
+-         StorageLive(_9);
+-         _9 = Point { x: const 12_u32, y: const 42_u32 };
+-         _8 = copy (_9.1: u32);
+-         StorageDead(_9);
 +         StorageLive(_10);
++         StorageLive(_11);
 +         nop;
-+         _9 = const 12_u32;
-+         _10 = const 42_u32;
++         _10 = const 12_u32;
++         _11 = const 42_u32;
 +         nop;
-+         _7 = copy _10;
-+         StorageDead(_9);
++         _8 = copy _11;
 +         StorageDead(_10);
++         StorageDead(_11);
 +         nop;
-          StorageDead(_7);
+          StorageDead(_8);
           StorageDead(_3);
           StorageDead(_1);
           return;
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff
index 6e36386bea6..a2fb3b979e6 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff
@@ -7,18 +7,19 @@
       let mut _2: (i32, bool);
       let mut _4: [i32; 6];
       let _5: usize;
-      let mut _6: bool;
-      let mut _8: Point;
-+     let mut _9: u32;
+      let mut _6: usize;
+      let mut _7: bool;
+      let mut _9: Point;
 +     let mut _10: u32;
++     let mut _11: u32;
       scope 1 {
           debug x => _1;
           let _3: i32;
           scope 2 {
               debug y => _3;
-              let _7: u32;
+              let _8: u32;
               scope 3 {
-                  debug z => _7;
+                  debug z => _8;
               }
           }
       }
@@ -36,30 +37,31 @@
           _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32];
           StorageLive(_5);
           _5 = const 3_usize;
-          _6 = Lt(copy _5, const 6_usize);
-          assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind continue];
+          _6 = const 6_usize;
+          _7 = Lt(copy _5, copy _6);
+          assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind continue];
       }
   
       bb2: {
           _3 = copy _4[_5];
           StorageDead(_5);
           StorageDead(_4);
-          StorageLive(_7);
--         StorageLive(_8);
--         _8 = Point { x: const 12_u32, y: const 42_u32 };
--         _7 = copy (_8.1: u32);
--         StorageDead(_8);
-+         StorageLive(_9);
+          StorageLive(_8);
+-         StorageLive(_9);
+-         _9 = Point { x: const 12_u32, y: const 42_u32 };
+-         _8 = copy (_9.1: u32);
+-         StorageDead(_9);
 +         StorageLive(_10);
++         StorageLive(_11);
 +         nop;
-+         _9 = const 12_u32;
-+         _10 = const 42_u32;
++         _10 = const 12_u32;
++         _11 = const 42_u32;
 +         nop;
-+         _7 = copy _10;
-+         StorageDead(_9);
++         _8 = copy _11;
 +         StorageDead(_10);
++         StorageDead(_11);
 +         nop;
-          StorageDead(_7);
+          StorageDead(_8);
           StorageDead(_3);
           StorageDead(_1);
           return;
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-abort.diff
index f7fe08831b9..e2420a341e0 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-abort.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-abort.diff
@@ -7,18 +7,19 @@
       let mut _2: (i32, bool);
       let mut _4: [i32; 6];
       let _5: usize;
-      let mut _6: bool;
-      let mut _8: Point;
-+     let mut _9: u32;
+      let mut _6: usize;
+      let mut _7: bool;
+      let mut _9: Point;
 +     let mut _10: u32;
++     let mut _11: u32;
       scope 1 {
           debug x => _1;
           let _3: i32;
           scope 2 {
               debug y => _3;
-              let _7: u32;
+              let _8: u32;
               scope 3 {
-                  debug z => _7;
+                  debug z => _8;
               }
           }
       }
@@ -36,30 +37,31 @@
           _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32];
           StorageLive(_5);
           _5 = const 3_usize;
-          _6 = Lt(copy _5, const 6_usize);
-          assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind unreachable];
+          _6 = const 6_usize;
+          _7 = Lt(copy _5, copy _6);
+          assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind unreachable];
       }
   
       bb2: {
           _3 = copy _4[_5];
           StorageDead(_5);
           StorageDead(_4);
-          StorageLive(_7);
--         StorageLive(_8);
--         _8 = Point { x: const 12_u32, y: const 42_u32 };
--         _7 = copy (_8.1: u32);
--         StorageDead(_8);
-+         StorageLive(_9);
+          StorageLive(_8);
+-         StorageLive(_9);
+-         _9 = Point { x: const 12_u32, y: const 42_u32 };
+-         _8 = copy (_9.1: u32);
+-         StorageDead(_9);
 +         StorageLive(_10);
++         StorageLive(_11);
 +         nop;
-+         _9 = const 12_u32;
-+         _10 = const 42_u32;
++         _10 = const 12_u32;
++         _11 = const 42_u32;
 +         nop;
-+         _7 = copy _10;
-+         StorageDead(_9);
++         _8 = copy _11;
 +         StorageDead(_10);
++         StorageDead(_11);
 +         nop;
-          StorageDead(_7);
+          StorageDead(_8);
           StorageDead(_3);
           StorageDead(_1);
           return;
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff
index 6e36386bea6..a2fb3b979e6 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff
@@ -7,18 +7,19 @@
       let mut _2: (i32, bool);
       let mut _4: [i32; 6];
       let _5: usize;
-      let mut _6: bool;
-      let mut _8: Point;
-+     let mut _9: u32;
+      let mut _6: usize;
+      let mut _7: bool;
+      let mut _9: Point;
 +     let mut _10: u32;
++     let mut _11: u32;
       scope 1 {
           debug x => _1;
           let _3: i32;
           scope 2 {
               debug y => _3;
-              let _7: u32;
+              let _8: u32;
               scope 3 {
-                  debug z => _7;
+                  debug z => _8;
               }
           }
       }
@@ -36,30 +37,31 @@
           _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32];
           StorageLive(_5);
           _5 = const 3_usize;
-          _6 = Lt(copy _5, const 6_usize);
-          assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind continue];
+          _6 = const 6_usize;
+          _7 = Lt(copy _5, copy _6);
+          assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind continue];
       }
   
       bb2: {
           _3 = copy _4[_5];
           StorageDead(_5);
           StorageDead(_4);
-          StorageLive(_7);
--         StorageLive(_8);
--         _8 = Point { x: const 12_u32, y: const 42_u32 };
--         _7 = copy (_8.1: u32);
--         StorageDead(_8);
-+         StorageLive(_9);
+          StorageLive(_8);
+-         StorageLive(_9);
+-         _9 = Point { x: const 12_u32, y: const 42_u32 };
+-         _8 = copy (_9.1: u32);
+-         StorageDead(_9);
 +         StorageLive(_10);
++         StorageLive(_11);
 +         nop;
-+         _9 = const 12_u32;
-+         _10 = const 42_u32;
++         _10 = const 12_u32;
++         _11 = const 42_u32;
 +         nop;
-+         _7 = copy _10;
-+         StorageDead(_9);
++         _8 = copy _11;
 +         StorageDead(_10);
++         StorageDead(_11);
 +         nop;
-          StorageDead(_7);
+          StorageDead(_8);
           StorageDead(_3);
           StorageDead(_1);
           return;
diff --git a/tests/mir-opt/pre-codegen/slice_index.rs b/tests/mir-opt/pre-codegen/slice_index.rs
index 5dac535d195..574062d6c35 100644
--- a/tests/mir-opt/pre-codegen/slice_index.rs
+++ b/tests/mir-opt/pre-codegen/slice_index.rs
@@ -9,7 +9,7 @@ use std::ops::Range;
 // EMIT_MIR slice_index.slice_index_usize.PreCodegen.after.mir
 pub fn slice_index_usize(slice: &[u32], index: usize) -> u32 {
     // CHECK-LABEL: slice_index_usize
-    // CHECK: [[LEN:_[0-9]+]] = PtrMetadata(copy _1)
+    // CHECK: [[LEN:_[0-9]+]] = Len((*_1))
     // CHECK: Lt(copy _2, copy [[LEN]])
     // CHECK-NOT: precondition_check
     // CHECK: _0 = copy (*_1)[_2];
diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-abort.mir
index 81e60b8ec2c..cc1034229fc 100644
--- a/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-abort.mir
@@ -8,7 +8,7 @@ fn slice_index_usize(_1: &[u32], _2: usize) -> u32 {
     let mut _4: bool;
 
     bb0: {
-        _3 = PtrMetadata(copy _1);
+        _3 = Len((*_1));
         _4 = Lt(copy _2, copy _3);
         assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, copy _2) -> [success: bb1, unwind unreachable];
     }
diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-unwind.mir
index c0fdc839608..358226fb529 100644
--- a/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-unwind.mir
@@ -8,7 +8,7 @@ fn slice_index_usize(_1: &[u32], _2: usize) -> u32 {
     let mut _4: bool;
 
     bb0: {
-        _3 = PtrMetadata(copy _1);
+        _3 = Len((*_1));
         _4 = Lt(copy _2, copy _3);
         assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, copy _2) -> [success: bb1, unwind continue];
     }
diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir
index 151783969dd..ecac03ad0f9 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir
@@ -7,19 +7,20 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
     let mut _3: usize;
     let mut _4: usize;
     let mut _9: std::option::Option<usize>;
-    let mut _11: bool;
-    let mut _13: &impl Fn(usize, &T);
-    let mut _14: (usize, &T);
-    let _15: ();
+    let mut _11: usize;
+    let mut _12: bool;
+    let mut _14: &impl Fn(usize, &T);
+    let mut _15: (usize, &T);
+    let _16: ();
     scope 1 {
         debug ((iter: std::ops::Range<usize>).0: usize) => _4;
         debug ((iter: std::ops::Range<usize>).1: usize) => _3;
         let _10: usize;
         scope 2 {
             debug i => _10;
-            let _12: &T;
+            let _13: &T;
             scope 3 {
-                debug x => _12;
+                debug x => _13;
             }
         }
         scope 5 (inlined iter::range::<impl Iterator for std::ops::Range<usize>>::next) {
@@ -81,22 +82,23 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
         StorageDead(_6);
         StorageDead(_7);
         _10 = copy ((_9 as Some).0: usize);
-        _11 = Lt(copy _10, copy _3);
-        assert(move _11, "index out of bounds: the length is {} but the index is {}", copy _3, copy _10) -> [success: bb6, unwind unreachable];
+        _11 = Len((*_1));
+        _12 = Lt(copy _10, copy _11);
+        assert(move _12, "index out of bounds: the length is {} but the index is {}", move _11, copy _10) -> [success: bb6, unwind unreachable];
     }
 
     bb6: {
-        _12 = &(*_1)[_10];
-        StorageLive(_13);
-        _13 = &_2;
+        _13 = &(*_1)[_10];
         StorageLive(_14);
-        _14 = (copy _10, copy _12);
-        _15 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _13, move _14) -> [return: bb7, unwind unreachable];
+        _14 = &_2;
+        StorageLive(_15);
+        _15 = (copy _10, copy _13);
+        _16 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _14, move _15) -> [return: bb7, unwind unreachable];
     }
 
     bb7: {
+        StorageDead(_15);
         StorageDead(_14);
-        StorageDead(_13);
         StorageDead(_9);
         goto -> bb1;
     }
diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir
index 006329dc20d..1032473b9b2 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir
@@ -7,19 +7,20 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
     let mut _3: usize;
     let mut _4: usize;
     let mut _9: std::option::Option<usize>;
-    let mut _11: bool;
-    let mut _13: &impl Fn(usize, &T);
-    let mut _14: (usize, &T);
-    let _15: ();
+    let mut _11: usize;
+    let mut _12: bool;
+    let mut _14: &impl Fn(usize, &T);
+    let mut _15: (usize, &T);
+    let _16: ();
     scope 1 {
         debug ((iter: std::ops::Range<usize>).0: usize) => _4;
         debug ((iter: std::ops::Range<usize>).1: usize) => _3;
         let _10: usize;
         scope 2 {
             debug i => _10;
-            let _12: &T;
+            let _13: &T;
             scope 3 {
-                debug x => _12;
+                debug x => _13;
             }
         }
         scope 5 (inlined iter::range::<impl Iterator for std::ops::Range<usize>>::next) {
@@ -81,22 +82,23 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
         StorageDead(_6);
         StorageDead(_7);
         _10 = copy ((_9 as Some).0: usize);
-        _11 = Lt(copy _10, copy _3);
-        assert(move _11, "index out of bounds: the length is {} but the index is {}", copy _3, copy _10) -> [success: bb6, unwind: bb8];
+        _11 = Len((*_1));
+        _12 = Lt(copy _10, copy _11);
+        assert(move _12, "index out of bounds: the length is {} but the index is {}", move _11, copy _10) -> [success: bb6, unwind: bb8];
     }
 
     bb6: {
-        _12 = &(*_1)[_10];
-        StorageLive(_13);
-        _13 = &_2;
+        _13 = &(*_1)[_10];
         StorageLive(_14);
-        _14 = (copy _10, copy _12);
-        _15 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _13, move _14) -> [return: bb7, unwind: bb8];
+        _14 = &_2;
+        StorageLive(_15);
+        _15 = (copy _10, copy _13);
+        _16 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _14, move _15) -> [return: bb7, unwind: bb8];
     }
 
     bb7: {
+        StorageDead(_15);
         StorageDead(_14);
-        StorageDead(_13);
         StorageDead(_9);
         goto -> bb1;
     }
diff --git a/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff b/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff
index e9eea69377f..05ad9dbf3cc 100644
--- a/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff
+++ b/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff
@@ -92,7 +92,7 @@
           StorageDead(_7);
 -         StorageDead(_6);
 -         StorageLive(_10);
-          StorageLive(_11);
+-         StorageLive(_11);
 -         StorageLive(_12);
           StorageLive(_13);
           _26 = const debuginfo::promoted[0];
@@ -105,8 +105,9 @@
       bb5: {
           StorageDead(_15);
           StorageDead(_13);
-          _11 = &(*_12);
-          _16 = PtrMetadata(copy _11);
+-         _11 = &(*_12);
+-         _16 = Len((*_11));
++         _16 = Len((*_12));
           _17 = const 3_usize;
           _18 = Ge(move _16, move _17);
           switchInt(move _18) -> [0: bb7, otherwise: bb6];
@@ -136,7 +137,7 @@
   
       bb8: {
 -         StorageDead(_12);
-          StorageDead(_11);
+-         StorageDead(_11);
 -         StorageDead(_10);
           StorageLive(_22);
           StorageLive(_23);
diff --git a/tests/run-make/cat-and-grep-sanity-check/Makefile b/tests/run-make/cat-and-grep-sanity-check/Makefile
deleted file mode 100644
index 8ee69c0a0de..00000000000
--- a/tests/run-make/cat-and-grep-sanity-check/Makefile
+++ /dev/null
@@ -1,50 +0,0 @@
-# grep in run-make tests was partially replaced with a custom script, CGREP. This tests that CGREP does its job correctly.
-# See https://github.com/rust-lang/rust/commit/ab788a2ee175c7560f0ca58bbc183ecfd57d2f7a
-# FIXME(Oneirical): Note that this test will likely become useless after the port to rmake.rs tests (see https://github.com/rust-lang/rust/issues/121876)
-
-include ../tools.mk
-
-all:
-	echo a | $(CGREP) a
-	! echo b | $(CGREP) a
-	echo xyz | $(CGREP) x y z
-	! echo abc | $(CGREP) b c d
-	printf "x\ny\nz" | $(CGREP) x y z
-
-	echo AbCd | $(CGREP) -i a b C D
-	! echo AbCd | $(CGREP) a b C D
-
-	true | $(CGREP) -v nothing
-	! echo nothing | $(CGREP) -v nothing
-	! echo xyz | $(CGREP) -v w x y
-	! echo xyz | $(CGREP) -v x y z
-	echo xyz | $(CGREP) -v a b c
-
-	! echo 'foo bar baz' | $(CGREP) 'foo baz'
-	echo 'foo bar baz' | $(CGREP) foo baz
-	echo 'x a `b` c y z' | $(CGREP) 'a `b` c'
-
-	echo baaac | $(CGREP) -e 'ba*c'
-	echo bc | $(CGREP) -e 'ba*c'
-	! echo aaac | $(CGREP) -e 'ba*c'
-
-	echo aaa | $(CGREP) -e 'a+'
-	! echo bbb | $(CGREP) -e 'a+'
-
-	echo abc | $(CGREP) -e 'a|e|i|o|u'
-	! echo fgh | $(CGREP) -e 'a|e|i|o|u'
-	echo abc | $(CGREP) -e '[aeiou]'
-	! echo fgh | $(CGREP) -e '[aeiou]'
-	! echo abc | $(CGREP) -e '[^aeiou]{3}'
-	echo fgh | $(CGREP) -e '[^aeiou]{3}'
-	echo ab cd ef gh | $(CGREP) -e '\bcd\b'
-	! echo abcdefgh | $(CGREP) -e '\bcd\b'
-	echo xyz | $(CGREP) -e '...'
-	! echo xy | $(CGREP) -e '...'
-	! echo xyz | $(CGREP) -e '\.\.\.'
-	echo ... | $(CGREP) -e '\.\.\.'
-
-	echo foo bar baz | $(CGREP) -e 'foo.*baz'
-	! echo foo bar baz | $(CGREP) -ve 'foo.*baz'
-	! echo foo bar baz | $(CGREP) -e 'baz.*foo'
-	echo foo bar baz | $(CGREP) -ve 'baz.*foo'
diff --git a/tests/run-make/crate-circular-deps-link/c.rs b/tests/run-make/crate-circular-deps-link/c.rs
index 9d72657aa59..cfe00a2a347 100644
--- a/tests/run-make/crate-circular-deps-link/c.rs
+++ b/tests/run-make/crate-circular-deps-link/c.rs
@@ -1,5 +1,5 @@
 #![crate_type = "bin"]
-#![feature(start)]
+#![no_main]
 #![no_std]
 
 extern crate a;
@@ -24,8 +24,8 @@ unsafe impl GlobalAlloc for Allocator {
 #[global_allocator]
 static ALLOCATOR: Allocator = Allocator;
 
-#[start]
-fn main(argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int {
     let mut v = Vec::new();
     for i in 0..argc {
         v.push(i);
diff --git a/tests/run-make/fmt-write-bloat/main.rs b/tests/run-make/fmt-write-bloat/main.rs
index 6f206d6515a..b50461c0a02 100644
--- a/tests/run-make/fmt-write-bloat/main.rs
+++ b/tests/run-make/fmt-write-bloat/main.rs
@@ -1,5 +1,5 @@
 #![feature(lang_items)]
-#![feature(start)]
+#![no_main]
 #![no_std]
 
 use core::fmt;
@@ -17,8 +17,8 @@ impl fmt::Write for Dummy {
     }
 }
 
-#[start]
-fn main(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int {
     let _ = writeln!(Dummy, "Hello World");
     0
 }
diff --git a/tests/run-make/glibc-symbols-x86_64-unknown-linux-gnu/rmake.rs b/tests/run-make/glibc-symbols-x86_64-unknown-linux-gnu/rmake.rs
new file mode 100644
index 00000000000..0134457c5c2
--- /dev/null
+++ b/tests/run-make/glibc-symbols-x86_64-unknown-linux-gnu/rmake.rs
@@ -0,0 +1,112 @@
+// Check that the compiler toolchain (rustc) that we distribute is not using newer glibc
+// symbols than a specified minimum.
+// This test should only be executed on an extracted dist archive or in a dist-* CI job.
+
+//@ only-dist
+//@ only-x86_64-unknown-linux-gnu
+//@ ignore-cross-compile
+
+use std::path::{Path, PathBuf};
+
+use run_make_support::{cmd, llvm_objdump, regex, rustc_path};
+
+fn main() {
+    // This is the maximum glibc version that we are *permitted* to use for the
+    // x86_64-unknown-linux-gnu target.
+    // All glibc symbols used in the compiler must be lower or equal than this version.
+    // So that if a given machine only has glibc 2.17, it is able to run the compiler.
+    let max_supported = (2, 17, 99);
+
+    let rustc = PathBuf::from(rustc_path());
+    // Check symbols directly in rustc
+    check_symbols(&rustc, max_supported);
+
+    // Find dynamic libraries referenced by rustc that come from our lib directory
+    let lib_path = rustc.parent().unwrap().parent().unwrap().join("lib");
+    let dynamic_libs = find_dynamic_libs(&rustc)
+        .into_iter()
+        .filter_map(|path| path.canonicalize().ok())
+        .filter(|lib| lib.starts_with(&lib_path))
+        .collect::<Vec<_>>();
+    for lib in dynamic_libs {
+        check_symbols(&lib, max_supported);
+    }
+}
+
+#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)]
+struct GlibcSymbol {
+    name: String,
+    version: (u32, u32, u32),
+}
+
+fn find_dynamic_libs(path: &Path) -> Vec<PathBuf> {
+    cmd("ldd")
+        .arg(path)
+        .run()
+        .stdout_utf8()
+        .lines()
+        .filter_map(|line| {
+            let line = line.trim();
+            let Some((_, line)) = line.split_once(" => ") else {
+                return None;
+            };
+            line.split_ascii_whitespace().next().map(|path| PathBuf::from(path))
+        })
+        .collect()
+}
+
+fn check_symbols(file: &Path, max_supported: (u32, u32, u32)) {
+    println!("Checking {}", file.display());
+    let mut invalid: Vec<GlibcSymbol> = get_glibc_symbols(file)
+        .into_iter()
+        .filter(|symbol| symbol.version > max_supported)
+        .collect();
+    if !invalid.is_empty() {
+        invalid.sort();
+        panic!(
+            "Found invalid glibc symbols in {}:\n{}",
+            file.display(),
+            invalid
+                .into_iter()
+                .map(|symbol| format!(
+                    "{} ({:?} higher than max allowed {:?})",
+                    symbol.name, symbol.version, max_supported
+                ))
+                .collect::<Vec<_>>()
+                .join("\n")
+        )
+    }
+}
+
+fn get_glibc_symbols(file: &Path) -> Vec<GlibcSymbol> {
+    let regex = regex::Regex::new(r#"GLIBC_(\d)+\.(\d+)(:?\.(\d+))?"#).unwrap();
+
+    // FIXME(kobzol): llvm-objdump currently chokes on the BOLTed librustc_driver.so file.
+    // Use objdump instead, since it seems to work, and we only run this test in a specific
+    // CI environment anyway.
+    cmd("objdump")
+        .arg("--dynamic-syms")
+        .arg(file)
+        .run()
+        .stdout_utf8()
+        .lines()
+        .filter_map(|line| {
+            // Example line
+            // 0000000000000000 DF *UND* 0000000000000000 (GLIBC_2.2.5) sbrk
+            let mut parts = line.split(" ").collect::<Vec<_>>().into_iter().rev();
+            let Some(name) = parts.next() else {
+                return None;
+            };
+            let Some(lib) = parts.next() else {
+                return None;
+            };
+            let Some(version) = regex.captures(lib) else {
+                return None;
+            };
+            let major = version.get(1).and_then(|m| m.as_str().parse().ok()).unwrap_or(0);
+            let minor = version.get(2).and_then(|m| m.as_str().parse().ok()).unwrap_or(0);
+            let patch = version.get(3).and_then(|m| m.as_str().parse().ok()).unwrap_or(0);
+            Some(GlibcSymbol { version: (major, minor, patch), name: name.to_string() })
+        })
+        .collect()
+}
diff --git a/tests/run-make/jobserver-error/Makefile b/tests/run-make/jobserver-error/Makefile
deleted file mode 100644
index 9f34970f96f..00000000000
--- a/tests/run-make/jobserver-error/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-include ../tools.mk
-
-# only-linux
-# ignore-cross-compile
-
-# Test compiler behavior in case environment specifies wrong jobserver.
-# Note that by default, the compiler uses file descriptors 0 (stdin), 1 (stdout), 2 (stderr),
-# but also 3 and 4 for either end of the ctrl-c signal handler self-pipe.
-
-all:
-	bash -c 'echo "fn main() {}" | MAKEFLAGS="--jobserver-auth=5,5" $(RUSTC)' 2>&1 | diff cannot_open_fd.stderr -
-	bash -c 'echo "fn main() {}" | MAKEFLAGS="--jobserver-auth=3,3" $(RUSTC) - 3</dev/null' 2>&1 | diff not_a_pipe.stderr -
-
-# This test randomly fails, see https://github.com/rust-lang/rust/issues/110321
-disabled:
-	bash -c 'echo "fn main() {}" | MAKEFLAGS="--jobserver-auth=3,3" $(RUSTC) - 3< <(cat /dev/null)' 2>&1 | diff poisoned_pipe.stderr -
-
diff --git a/tests/run-make/jobserver-error/cannot_open_fd.stderr b/tests/run-make/jobserver-error/cannot_open_fd.stderr
index 9ac4c1c58f7..d075057b3d3 100644
--- a/tests/run-make/jobserver-error/cannot_open_fd.stderr
+++ b/tests/run-make/jobserver-error/cannot_open_fd.stderr
@@ -1,4 +1,4 @@
-warning: failed to connect to jobserver from environment variable `MAKEFLAGS="--jobserver-auth=5,5"`: cannot open file descriptor 5 from the jobserver environment variable value: Bad file descriptor (os error 9)
+warning: failed to connect to jobserver from environment variable `MAKEFLAGS="--jobserver-auth=1000,1000"`: cannot open file descriptor 1000 from the jobserver environment variable value: Bad file descriptor (os error 9)
   |
   = note: the build environment is likely misconfigured
 
diff --git a/tests/run-make/jobserver-error/rmake.rs b/tests/run-make/jobserver-error/rmake.rs
new file mode 100644
index 00000000000..14ee24c7148
--- /dev/null
+++ b/tests/run-make/jobserver-error/rmake.rs
@@ -0,0 +1,47 @@
+// ignore-tidy-linelength
+//! If the environment variables contain an invalid `jobserver-auth`, this used to cause an ICE
+//! until this was fixed in [do not panic on failure to acquire jobserver token
+//! #109694](https://github.com/rust-lang/rust/pull/109694).
+//!
+//! Proper handling has been added, and this test checks that helpful warnings and errors are
+//! printed instead in case of a wrong jobserver. See
+//! <https://github.com/rust-lang/rust/issues/46981>.
+
+//@ only-linux
+//@ ignore-cross-compile
+
+#![deny(warnings)]
+
+use run_make_support::{diff, rustc};
+
+fn main() {
+    let out = rustc()
+        .stdin_buf(("fn main() {}").as_bytes())
+        .env("MAKEFLAGS", "--jobserver-auth=1000,1000")
+        .run_fail()
+        .stderr_utf8();
+    diff().expected_file("cannot_open_fd.stderr").actual_text("actual", out).run();
+
+    let out = rustc()
+        .stdin_buf(("fn main() {}").as_bytes())
+        .input("-")
+        .env("MAKEFLAGS", "--jobserver-auth=3,3")
+        .set_aux_fd(3, std::fs::File::open("/dev/null").unwrap())
+        .run()
+        .stderr_utf8();
+    diff().expected_file("not_a_pipe.stderr").actual_text("actual", out).run();
+
+    // FIXME(#110321): the Makefile version had a disabled check:
+    //
+    // ```makefile
+    // bash -c 'echo "fn main() {}" | MAKEFLAGS="--jobserver-auth=3,3" $(RUSTC) - 3< <(cat /dev/null)' 2>&1 | diff poisoned_pipe.stderr -
+    // ```
+    //
+    // > the jobserver helper thread launched here gets starved out and doesn't run, while the
+    // > coordinator thread continually processes work using the implicit jobserver token, never
+    // > yielding long enough for the jobserver helper to do its work (and process the error).
+    //
+    // but is not necessarily worth fixing as it might require changing coordinator behavior that
+    // might regress performance. See discussion at
+    // <https://github.com/rust-lang/rust/issues/110321#issuecomment-1636914956>.
+}
diff --git a/tests/run-make/llvm-location-discriminator-limit-dummy-span/main.rs b/tests/run-make/llvm-location-discriminator-limit-dummy-span/main.rs
new file mode 100644
index 00000000000..421eb4331b3
--- /dev/null
+++ b/tests/run-make/llvm-location-discriminator-limit-dummy-span/main.rs
@@ -0,0 +1,3 @@
+fn main() {
+    other::big_function();
+}
diff --git a/tests/run-make/llvm-location-discriminator-limit-dummy-span/other.rs b/tests/run-make/llvm-location-discriminator-limit-dummy-span/other.rs
new file mode 100644
index 00000000000..a3ff578ebe4
--- /dev/null
+++ b/tests/run-make/llvm-location-discriminator-limit-dummy-span/other.rs
@@ -0,0 +1 @@
+proc::declare_big_function!();
diff --git a/tests/run-make/llvm-location-discriminator-limit-dummy-span/proc.rs b/tests/run-make/llvm-location-discriminator-limit-dummy-span/proc.rs
new file mode 100644
index 00000000000..59d17a9be59
--- /dev/null
+++ b/tests/run-make/llvm-location-discriminator-limit-dummy-span/proc.rs
@@ -0,0 +1,7 @@
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn declare_big_function(_input: TokenStream) -> TokenStream {
+    include_str!("./generated.rs").parse().unwrap()
+}
diff --git a/tests/run-make/llvm-location-discriminator-limit-dummy-span/rmake.rs b/tests/run-make/llvm-location-discriminator-limit-dummy-span/rmake.rs
new file mode 100644
index 00000000000..2727effe818
--- /dev/null
+++ b/tests/run-make/llvm-location-discriminator-limit-dummy-span/rmake.rs
@@ -0,0 +1,65 @@
+//! Regression test for <https://github.com/rust-lang/rust/issues/135332>.
+//!
+//! We can't simply drop debuginfo location spans when LLVM's location discriminator value limit is
+//! reached. Otherwise, with `-Z verify-llvm-ir` and fat LTO, LLVM will report a broken module for
+//!
+//! ```text
+//! inlinable function call in a function with debug info must have a !dbg location
+//! ```
+
+//@ ignore-cross-compile
+//@ needs-dynamic-linking
+//@ only-nightly (requires unstable rustc flag)
+
+#![deny(warnings)]
+
+use run_make_support::{dynamic_lib_name, rfs, rust_lib_name, rustc};
+
+// Synthesize a function that will have a large (`n`) number of functions
+// MIR-inlined into it. When combined with a proc-macro, all of these inline
+// callsites will have the same span, forcing rustc to use the DWARF
+// discriminator to distinguish between them. LLVM's capacity to store that
+// discriminator is not infinite (currently it allocates 12 bits for a
+// maximum value of 4096) so if this function gets big enough rustc's error
+// handling path will be exercised.
+fn generate_program(n: u32) -> String {
+    let mut program = String::from("pub type BigType = Vec<Vec<String>>;\n\n");
+    program.push_str("pub fn big_function() -> BigType {\n");
+    program.push_str("    vec![\n");
+    for i in 1..=n {
+        program.push_str(&format!("vec![\"string{}\".to_owned()],\n", i));
+    }
+    program.push_str("    ]\n");
+    program.push_str("}\n");
+    program
+}
+
+fn main() {
+    // The reported threshold is around 1366 (4096/3), but let's bump it to
+    // around 1500 to be less sensitive.
+    rfs::write("generated.rs", generate_program(1500));
+
+    rustc()
+        .input("proc.rs")
+        .crate_type("proc-macro")
+        .edition("2021")
+        .arg("-Cdebuginfo=line-tables-only")
+        .run();
+    rustc()
+        .extern_("proc", dynamic_lib_name("proc"))
+        .input("other.rs")
+        .crate_type("rlib")
+        .edition("2021")
+        .opt_level("3")
+        .arg("-Cdebuginfo=line-tables-only")
+        .run();
+    rustc()
+        .extern_("other", rust_lib_name("other"))
+        .input("main.rs")
+        .edition("2021")
+        .opt_level("3")
+        .arg("-Cdebuginfo=line-tables-only")
+        .arg("-Clto=fat")
+        .arg("-Zverify-llvm-ir")
+        .run();
+}
diff --git a/tests/run-make/no-alloc-shim/foo.rs b/tests/run-make/no-alloc-shim/foo.rs
index a3daec3db39..42606961f8b 100644
--- a/tests/run-make/no-alloc-shim/foo.rs
+++ b/tests/run-make/no-alloc-shim/foo.rs
@@ -35,7 +35,7 @@ unsafe impl GlobalAlloc for Alloc {
 static __rust_no_alloc_shim_is_unstable: u8 = 0;
 
 #[no_mangle]
-extern "C" fn main(_argc: usize, _argv: *const *const i8) -> i32 {
+extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const i8) -> i32 {
     unsafe {
         assert_eq!(alloc::alloc::alloc(Layout::new::<()>()), core::ptr::null_mut());
     }
diff --git a/tests/run-make/sepcomp-inlining/foo.rs b/tests/run-make/sepcomp-inlining/foo.rs
index 2fe5f9cb726..9101ee691a4 100644
--- a/tests/run-make/sepcomp-inlining/foo.rs
+++ b/tests/run-make/sepcomp-inlining/foo.rs
@@ -1,4 +1,4 @@
-#![feature(start)]
+#![crate_type = "lib"]
 
 #[inline]
 fn inlined() -> u32 {
@@ -21,8 +21,7 @@ mod b {
     }
 }
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+pub fn start(_: isize, _: *const *const u8) -> isize {
     a::f();
     b::f();
 
diff --git a/tests/rustdoc-gui/huge-collection-of-constants.goml b/tests/rustdoc-gui/huge-collection-of-constants.goml
index 387aca6f66c..643f0f51ac1 100644
--- a/tests/rustdoc-gui/huge-collection-of-constants.goml
+++ b/tests/rustdoc-gui/huge-collection-of-constants.goml
@@ -3,7 +3,7 @@
 go-to: "file://" + |DOC_PATH| + "/test_docs/huge_amount_of_consts/index.html"
 
 compare-elements-position-near-false: (
-    "//ul[@class='item-table']/li[last()-1]",
-    "//ul[@class='item-table']/li[last()-3]",
+    "//dl[@class='item-table']/dt[last()-1]",
+    "//dl[@class='item-table']/dt[last()-3]",
     {"y": 12},
 )
diff --git a/tests/rustdoc-gui/item-name-wrap.goml b/tests/rustdoc-gui/item-name-wrap.goml
index 825c16ac5b8..d4da5c2d609 100644
--- a/tests/rustdoc-gui/item-name-wrap.goml
+++ b/tests/rustdoc-gui/item-name-wrap.goml
@@ -3,21 +3,21 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/short_docs/index.html"
 set-window-size: (1000, 600)
 
 // First we ensure that there is only one `item-table`...
-assert-count: ("ul.item-table", 1)
+assert-count: ("dl.item-table", 1)
 // And only two items in it.
-assert-count: ("ul.item-table li", 2)
+assert-count: ("dl.item-table dt", 2)
 
 // If they don't have the same height, then it means one of the two is on two lines whereas it
 // shouldn't!
 compare-elements-size: (
-    ".item-table .item-name a[href='fn.mult_vec_num.html']",
-    ".item-table .item-name a[href='fn.subt_vec_num.html']",
+    ".item-table dt a[href='fn.mult_vec_num.html']",
+    ".item-table dt a[href='fn.subt_vec_num.html']",
     ["height"],
 )
 
 // We also check that the `item-table` is taking the full width.
 compare-elements-size: (
     "#functions",
-    "ul.item-table",
+    "dl.item-table",
     ["width"],
 )
diff --git a/tests/rustdoc-gui/item-summary-table.goml b/tests/rustdoc-gui/item-summary-table.goml
index 89306030329..7c0dfce3062 100644
--- a/tests/rustdoc-gui/item-summary-table.goml
+++ b/tests/rustdoc-gui/item-summary-table.goml
@@ -1,6 +1,6 @@
 // This test ensures that <table> elements aren't display in items summary.
 go-to: "file://" + |DOC_PATH| + "/lib2/summary_table/index.html"
 // We check that we picked the right item first.
-assert-text: (".item-table .item-name", "Foo")
+assert-text: (".item-table dt", "Foo")
 // Then we check that its summary is empty.
-assert-false: ".item-table .desc"
+assert-false: ".item-table dd"
diff --git a/tests/rustdoc-gui/label-next-to-symbol.goml b/tests/rustdoc-gui/label-next-to-symbol.goml
index a8363f29dd5..7960dac11b6 100644
--- a/tests/rustdoc-gui/label-next-to-symbol.goml
+++ b/tests/rustdoc-gui/label-next-to-symbol.goml
@@ -12,59 +12,59 @@ assert: (".stab.portability")
 
 // make sure that deprecated and portability have the right colors
 assert-css: (
-    ".item-table .item-name .stab.deprecated",
+    ".item-table dt .stab.deprecated",
     { "background-color": "#fff5d6" },
 )
 assert-css: (
-    ".item-table .item-name .stab.portability",
+    ".item-table dt .stab.portability",
     { "background-color": "#fff5d6" },
 )
 
 // table like view
-assert-css: (".desc.docblock-short", { "padding-left": "0px" })
+assert-css: ("dd", { "padding-left": "0px" })
 compare-elements-position-near: (
-    "//*[@class='item-name']//a[normalize-space()='replaced_function']",
-    ".item-name .stab.deprecated",
+    "//dt//a[normalize-space()='replaced_function']",
+    "dt .stab.deprecated",
     {"y": 2},
 )
 // "Unix" part is on second line
 compare-elements-position-false: (
-    ".item-name .stab.deprecated",
-    ".item-name .stab.portability",
+    "dt .stab.deprecated",
+    "dt .stab.portability",
     ["y"],
 )
 
 // Ensure no wrap
 compare-elements-position: (
-    "//*[@class='item-name']//a[normalize-space()='replaced_function']/..",
-    "//*[@class='desc docblock-short'][normalize-space()='a thing with a label']",
+    "//dt//a[normalize-space()='replaced_function']/..",
+    "//dd[normalize-space()='a thing with a label']",
     ["y"],
 )
 
 // Mobile view
 set-window-size: (600, 600)
 // staggered layout with 2em spacing
-assert-css: (".desc.docblock-short", { "padding-left": "32px" })
+assert-css: ("dd", { "padding-left": "32px" })
 compare-elements-position-near: (
-    "//*[@class='item-name']//a[normalize-space()='replaced_function']",
-    ".item-name .stab.deprecated",
+    "//dt//a[normalize-space()='replaced_function']",
+    "dt .stab.deprecated",
     {"y": 2},
 )
 compare-elements-position: (
-    ".item-name .stab.deprecated",
-    ".item-name .stab.portability",
+    "dt .stab.deprecated",
+    "dt .stab.portability",
     ["y"],
 )
 
 // Ensure wrap
 compare-elements-position-false: (
-    "//*[@class='item-name']//a[normalize-space()='replaced_function']/..",
-    "//*[@class='desc docblock-short'][normalize-space()='a thing with a label']",
+    "//dt//a[normalize-space()='replaced_function']/..",
+    "//dd[normalize-space()='a thing with a label']",
     ["y"],
 )
 compare-elements-position-false: (
-    ".item-name .stab.deprecated",
-    "//*[@class='desc docblock-short'][normalize-space()='a thing with a label']",
+    "dt .stab.deprecated",
+    "//dd[normalize-space()='a thing with a label']",
     ["y"],
 )
 
diff --git a/tests/rustdoc-gui/links-color.goml b/tests/rustdoc-gui/links-color.goml
index 8d26b826479..f11920cdd8c 100644
--- a/tests/rustdoc-gui/links-color.goml
+++ b/tests/rustdoc-gui/links-color.goml
@@ -37,9 +37,9 @@ define-function: (
             },
             ALL,
         )
-        move-cursor-to: ".desc a[href='long_code_block_link/index.html']"
+        move-cursor-to: "dd a[href='long_code_block_link/index.html']"
         assert-css: (
-            ".desc a[href='long_code_block_link/index.html']",
+            "dd a[href='long_code_block_link/index.html']",
             {"text-decoration": "underline solid " + |mod|},
         )
     },
diff --git a/tests/rustdoc-gui/module-items-font.goml b/tests/rustdoc-gui/module-items-font.goml
index 54c8131c3b9..0e6dd81c05b 100644
--- a/tests/rustdoc-gui/module-items-font.goml
+++ b/tests/rustdoc-gui/module-items-font.goml
@@ -1,67 +1,67 @@
 // This test checks that the correct font is used on module items (in index.html pages).
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 assert-css: (
-    ".item-table .item-name > a",
+    ".item-table dt > a",
     {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
     ALL,
 )
 assert-css: (
-    ".item-table .docblock-short",
+    ".item-table dd",
     {"font-family": '"Source Serif 4", NanumBarunGothic, serif'},
     ALL,
 )
 
 // modules
 assert-css: (
-    "#modules + .item-table .item-name a",
+    "#modules + .item-table dt a",
     {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
 )
 assert-css: (
-    "#modules + .item-table .desc.docblock-short",
+    "#modules + .item-table ",
     {"font-family": '"Source Serif 4", NanumBarunGothic, serif'},
 )
 // structs
 assert-css: (
-    "#structs + .item-table .item-name a",
+    "#structs + .item-table dt a",
     {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
 )
 assert-css: (
-    "#structs + .item-table .desc.docblock-short",
+    "#structs + .item-table dd",
     {"font-family": '"Source Serif 4", NanumBarunGothic, serif'},
 )
 // enums
 assert-css: (
-    "#enums + .item-table .item-name a",
+    "#enums + .item-table dt a",
     {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
 )
 assert-css: (
-    "#enums + .item-table .desc.docblock-short",
+    "#enums + .item-table dd",
     {"font-family": '"Source Serif 4", NanumBarunGothic, serif'},
 )
 // traits
 assert-css: (
-    "#traits + .item-table .item-name a",
+    "#traits + .item-table dt a",
     {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
 )
 assert-css: (
-    "#traits + .item-table .desc.docblock-short",
+    "#traits + .item-table dd",
     {"font-family": '"Source Serif 4", NanumBarunGothic, serif'},
 )
 // functions
 assert-css: (
-    "#functions + .item-table .item-name a",
+    "#functions + .item-table dt a",
     {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
 )
 assert-css: (
-    "#functions + .item-table .desc.docblock-short",
+    "#functions + .item-table dd",
     {"font-family": '"Source Serif 4", NanumBarunGothic, serif'},
 )
 // keywords
 assert-css: (
-    "#keywords + .item-table .item-name a",
+    "#keywords + .item-table dt a",
     {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
 )
 assert-css: (
-    "#keywords + .item-table .desc.docblock-short",
+    "#keywords + .item-table dd",
     {"font-family": '"Source Serif 4", NanumBarunGothic, serif'},
 )
diff --git a/tests/rustdoc-gui/sidebar.goml b/tests/rustdoc-gui/sidebar.goml
index bb7453fdeac..38160cc49d0 100644
--- a/tests/rustdoc-gui/sidebar.goml
+++ b/tests/rustdoc-gui/sidebar.goml
@@ -65,8 +65,8 @@ assert-text: (".sidebar-elems section ul > li:nth-child(8)", "Functions")
 assert-text: (".sidebar-elems section ul > li:nth-child(9)", "Type Aliases")
 assert-text: (".sidebar-elems section ul > li:nth-child(10)", "Unions")
 assert-text: (".sidebar-elems section ul > li:nth-child(11)", "Keywords")
-assert-text: ("#structs + .item-table .item-name > a", "Foo")
-click: "#structs + .item-table .item-name > a"
+assert-text: ("#structs + .item-table dt > a", "Foo")
+click: "#structs + .item-table dt > a"
 
 // PAGE: struct.Foo.html
 assert-count: (".sidebar .sidebar-crate", 1)
@@ -101,8 +101,8 @@ assert-text: (".sidebar-elems > section ul.block > li:nth-child(2)", "Structs")
 assert-text: (".sidebar-elems > section ul.block > li:nth-child(3)", "Traits")
 assert-text: (".sidebar-elems > section ul.block > li:nth-child(4)", "Functions")
 assert-text: (".sidebar-elems > section ul.block > li:nth-child(5)", "Type Aliases")
-assert-text: ("#functions + .item-table .item-name > a", "foobar")
-click: "#functions + .item-table .item-name > a"
+assert-text: ("#functions + .item-table dt > a", "foobar")
+click: "#functions + .item-table dt > a"
 
 // PAGE: fn.foobar.html
 // In items containing no items (like functions or constants) and in modules, we have no
@@ -145,7 +145,7 @@ assert-text: (".sidebar-elems ul.block > li.current > a", "sub_sub_module")
 // We check that we don't have the crate list.
 assert-false: ".sidebar-elems .crate"
 assert-text: (".sidebar-elems > section ul > li:nth-child(1)", "Functions")
-assert-text: ("#functions + .item-table .item-name > a", "foo")
+assert-text: ("#functions + .item-table dt > a", "foo")
 
 // Links to trait implementations in the sidebar should not wrap even if they are long.
 go-to: "file://" + |DOC_PATH| + "/lib2/struct.HasALongTraitWithParams.html"
diff --git a/tests/rustdoc-gui/unsafe-fn.goml b/tests/rustdoc-gui/unsafe-fn.goml
index b8b2e1e27f5..b857afeff13 100644
--- a/tests/rustdoc-gui/unsafe-fn.goml
+++ b/tests/rustdoc-gui/unsafe-fn.goml
@@ -17,7 +17,7 @@ define-function: (
     [theme, color],
     block {
         call-function: ("switch-theme", {"theme": |theme|})
-        assert-css: (".item-name sup", {"color": |color|})
+        assert-css: ("dt sup", {"color": |color|})
     },
 )
 
diff --git a/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.rs b/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.rs
index 571bc94e30f..db2ccefb0fb 100644
--- a/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.rs
+++ b/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.rs
@@ -1,4 +1,5 @@
 //@ compile-flags:--test
+//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
 //@ check-pass
 #![allow(rustdoc::invalid_codeblock_attributes)]
 
diff --git a/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.stdout b/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.stdout
index e5c27bebbdb..7326c0a25a0 100644
--- a/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.stdout
+++ b/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.stdout
@@ -1,5 +1,5 @@
 
 running 0 tests
 
-test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/tests/rustdoc-ui/invalid_const_in_lifetime_position.rs b/tests/rustdoc-ui/invalid_const_in_lifetime_position.rs
index 07fc239a8f8..427c84679ba 100644
--- a/tests/rustdoc-ui/invalid_const_in_lifetime_position.rs
+++ b/tests/rustdoc-ui/invalid_const_in_lifetime_position.rs
@@ -8,4 +8,4 @@ fn f<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}
 //~| ERROR associated type takes 0 generic arguments but 1 generic argument
 //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments
 //~| ERROR associated type takes 0 generic arguments but 1 generic argument
-//~| ERROR trait `X` cannot be made into an object
+//~| ERROR trait `X` is not dyn compatible
diff --git a/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr b/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr
index 0c3826c5665..180ba63927b 100644
--- a/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr
+++ b/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr
@@ -92,17 +92,18 @@ LL |     type Y<'a>;
    |          ^
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0038]: the trait `X` cannot be made into an object
+error[E0038]: the trait `X` is not dyn compatible
   --> $DIR/invalid_const_in_lifetime_position.rs:4:20
    |
 LL | fn f<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}
-   |                    ^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object
+   |                    ^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/invalid_const_in_lifetime_position.rs:2:10
    |
 LL | trait X {
-   |       - this trait cannot be made into an object...
+   |       - this trait is not dyn compatible...
 LL |     type Y<'a>;
    |          ^ ...because it contains the generic associated type `Y`
    = help: consider moving `Y` to another trait
diff --git a/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.rs b/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.rs
index 027574923c7..89b55beaea1 100644
--- a/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.rs
+++ b/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.rs
@@ -5,8 +5,8 @@ use std::ops::Index;
 pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
     //~^ expected 1 lifetime argument
     //~| expected 1 generic argument
-    //~| the trait `SVec` cannot be made into an object
-    //~| `SVec` cannot be made into an object
+    //~| the trait `SVec` is not dyn compatible
+    //~| `SVec` is not dyn compatible
     //~| missing generics for associated type `SVec::Item`
     //~| missing generics for associated type `SVec::Item`
     let _ = s;
diff --git a/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.stderr b/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.stderr
index f9080bf0785..72d1a52f710 100644
--- a/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.stderr
+++ b/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.stderr
@@ -294,19 +294,20 @@ help: add missing generic argument
 LL |     Output = <Self as SVec>::Item> as SVec>::Item<T>,
    |                                                  +++
 
-error[E0038]: the trait `SVec` cannot be made into an object
-  --> $DIR/ice-generic-type-alias-105742.rs:5:31
+error[E0038]: the trait `SVec` is not dyn compatible
+  --> $DIR/ice-generic-type-alias-105742.rs:5:35
    |
 LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SVec` cannot be made into an object
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^ `SVec` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/ice-generic-type-alias-105742.rs:15:17
    |
 LL |    pub trait SVec: Index<
    |  ____________----__^
    | |            |
-   | |            this trait cannot be made into an object...
+   | |            this trait is not dyn compatible...
 LL | |      <Self as SVec>::Item,
 ...  |
 LL | |/     Output = <Index<<Self as SVec>::Item,
diff --git a/tests/rustdoc/anonymous-reexport-108931.rs b/tests/rustdoc/anonymous-reexport-108931.rs
index f4cc7f12396..b995c89b614 100644
--- a/tests/rustdoc/anonymous-reexport-108931.rs
+++ b/tests/rustdoc/anonymous-reexport-108931.rs
@@ -16,7 +16,7 @@ mod bar {
 //@ count - '//*[@id="main-content"]/h2' 2
 //@ has - '//*[@id="main-content"]/h2' 'Re-exports'
 //@ has - '//*[@id="main-content"]/h2' 'Modules'
-//@ has - '//*[@id="main-content"]//*[@class="item-table"]//li//code' 'pub use foo::Foo as _;'
-//@ has - '//*[@id="main-content"]//*[@class="item-table"]//li//code' 'pub use bar::Bar as _;'
+//@ has - '//*[@id="main-content"]//*[@class="item-table reexports"]/dt//code' 'pub use foo::Foo as _;'
+//@ has - '//*[@id="main-content"]//*[@class="item-table reexports"]/dt//code' 'pub use bar::Bar as _;'
 pub use foo::Foo as _;
 pub use bar::Bar as _;
diff --git a/tests/rustdoc/anonymous-reexport.rs b/tests/rustdoc/anonymous-reexport.rs
index 8021008dc66..bf5fa93f953 100644
--- a/tests/rustdoc/anonymous-reexport.rs
+++ b/tests/rustdoc/anonymous-reexport.rs
@@ -9,7 +9,7 @@
 //@ has - '//*[@id="main-content"]/h2' 'Structs'
 //@ has - '//*[@id="main-content"]/h2' 'Re-exports'
 // The 3 re-exports.
-//@ count - '//*[@id="main-content"]//*[@class="item-table"]//li//code' 3
+//@ count - '//*[@id="main-content"]//*[@class="item-table reexports"]/dt//code' 3
 // The public struct.
 //@ count - '//*[@id="main-content"]//a[@class="struct"]' 1
 
diff --git a/tests/rustdoc/attributes-inlining-108281.rs b/tests/rustdoc/attributes-inlining-108281.rs
index ba6c570b59b..9dfaf1a6846 100644
--- a/tests/rustdoc/attributes-inlining-108281.rs
+++ b/tests/rustdoc/attributes-inlining-108281.rs
@@ -11,15 +11,15 @@ mod sub {
     pub fn public() {}
 }
 
-//@ matches - '//*[@class="desc docblock-short"]' '^Displayed$'
+//@ matches - '//dd' '^Displayed$'
 /// Displayed
 #[doc(inline)]
 pub use crate::bar as Bar;
-//@ matches - '//*[@class="desc docblock-short"]' '^Hello\sDisplayed$'
+//@ matches - '//dd' '^Hello\sDisplayed$'
 #[doc(inline)]
 /// Hello
 pub use crate::Bar as Bar2;
 
-//@ matches - '//*[@class="desc docblock-short"]' '^Public$'
+//@ matches - '//dd' '^Public$'
 /// Public
 pub use crate::sub::public as Public;
diff --git a/tests/rustdoc/cfg_doc_reexport.rs b/tests/rustdoc/cfg_doc_reexport.rs
index a07e4fe2f02..f8101e2a958 100644
--- a/tests/rustdoc/cfg_doc_reexport.rs
+++ b/tests/rustdoc/cfg_doc_reexport.rs
@@ -5,8 +5,8 @@
 #![no_core]
 
 //@ has 'foo/index.html'
-//@ has - '//*[@class="item-name"]/*[@class="stab portability"]' 'foobar'
-//@ has - '//*[@class="item-name"]/*[@class="stab portability"]' 'bar'
+//@ has - '//dt/*[@class="stab portability"]' 'foobar'
+//@ has - '//dt/*[@class="stab portability"]' 'bar'
 
 #[doc(cfg(feature = "foobar"))]
 mod imp_priv {
diff --git a/tests/rustdoc/deprecated.rs b/tests/rustdoc/deprecated.rs
index b39da9b440a..a84657a3df5 100644
--- a/tests/rustdoc/deprecated.rs
+++ b/tests/rustdoc/deprecated.rs
@@ -1,6 +1,5 @@
-//@ has deprecated/index.html '//*[@class="item-name"]/span[@class="stab deprecated"]' \
-//      'Deprecated'
-//@ has - '//*[@class="desc docblock-short"]' 'Deprecated docs'
+//@ has deprecated/index.html '//dt/span[@class="stab deprecated"]' 'Deprecated'
+//@ has - '//dd' 'Deprecated docs'
 
 //@ has deprecated/struct.S.html '//*[@class="stab deprecated"]' \
 //      'Deprecated since 1.0.0: text'
@@ -8,7 +7,7 @@
 #[deprecated(since = "1.0.0", note = "text")]
 pub struct S;
 
-//@ matches deprecated/index.html '//*[@class="desc docblock-short"]' '^Docs'
+//@ matches deprecated/index.html '//dd' '^Docs'
 /// Docs
 pub struct T;
 
diff --git a/tests/rustdoc/display-hidden-items.rs b/tests/rustdoc/display-hidden-items.rs
index d9f53435e46..40cd636e2fe 100644
--- a/tests/rustdoc/display-hidden-items.rs
+++ b/tests/rustdoc/display-hidden-items.rs
@@ -5,19 +5,19 @@
 #![crate_name = "foo"]
 
 //@ has 'foo/index.html'
-//@ has - '//*[@class="item-name"]/span[@title="Hidden item"]' '👻'
+//@ has - '//dt/span[@title="Hidden item"]' '👻'
 
 //@ has - '//*[@id="reexport.hidden_reexport"]/code' '#[doc(hidden)] pub use hidden::inside_hidden as hidden_reexport;'
 #[doc(hidden)]
 pub use hidden::inside_hidden as hidden_reexport;
 
-//@ has - '//*[@class="item-name"]/a[@class="trait"]' 'TraitHidden'
+//@ has - '//dt/a[@class="trait"]' 'TraitHidden'
 //@ has 'foo/trait.TraitHidden.html'
 //@ has - '//code' '#[doc(hidden)] pub trait TraitHidden'
 #[doc(hidden)]
 pub trait TraitHidden {}
 
-//@ has 'foo/index.html' '//*[@class="item-name"]/a[@class="trait"]' 'Trait'
+//@ has 'foo/index.html' '//dt/a[@class="trait"]' 'Trait'
 pub trait Trait {
     //@ has 'foo/trait.Trait.html'
     //@ has - '//*[@id="associatedconstant.BAR"]/*[@class="code-header"]' '#[doc(hidden)] const BAR: u32 = 0u32'
@@ -29,7 +29,7 @@ pub trait Trait {
     fn foo() {}
 }
 
-//@ has 'foo/index.html' '//*[@class="item-name"]/a[@class="struct"]' 'Struct'
+//@ has 'foo/index.html' '//dt/a[@class="struct"]' 'Struct'
 //@ has 'foo/struct.Struct.html'
 pub struct Struct {
     //@ has - '//*[@id="structfield.a"]/code' 'a: u32'
@@ -50,7 +50,7 @@ impl Trait for Struct {
 //@ has - '//*[@id="impl-TraitHidden-for-Struct"]/*[@class="code-header"]' 'impl TraitHidden for Struct'
 impl TraitHidden for Struct {}
 
-//@ has 'foo/index.html' '//*[@class="item-name"]/a[@class="enum"]' 'HiddenEnum'
+//@ has 'foo/index.html' '//dt/a[@class="enum"]' 'HiddenEnum'
 //@ has 'foo/enum.HiddenEnum.html'
 //@ has - '//code' '#[doc(hidden)] pub enum HiddenEnum'
 #[doc(hidden)]
@@ -58,18 +58,18 @@ pub enum HiddenEnum {
     A,
 }
 
-//@ has 'foo/index.html' '//*[@class="item-name"]/a[@class="enum"]' 'Enum'
+//@ has 'foo/index.html' '//dt/a[@class="enum"]' 'Enum'
 pub enum Enum {
     //@ has 'foo/enum.Enum.html' '//*[@id="variant.A"]/*[@class="code-header"]' 'A'
     #[doc(hidden)]
     A,
 }
 
-//@ has 'foo/index.html' '//*[@class="item-name"]/a[@class="mod"]' 'hidden'
+//@ has 'foo/index.html' '//dt/a[@class="mod"]' 'hidden'
 #[doc(hidden)]
 pub mod hidden {
     //@ has 'foo/hidden/index.html'
-    //@ has - '//*[@class="item-name"]/a[@class="fn"]' 'inside_hidden'
+    //@ has - '//dt/a[@class="fn"]' 'inside_hidden'
     //@ has 'foo/hidden/fn.inside_hidden.html'
     pub fn inside_hidden() {}
 }
diff --git a/tests/rustdoc/doc-cfg.rs b/tests/rustdoc/doc-cfg.rs
index 6c973b5666b..652c8419b4f 100644
--- a/tests/rustdoc/doc-cfg.rs
+++ b/tests/rustdoc/doc-cfg.rs
@@ -12,7 +12,7 @@ pub struct Portable;
 //@ has doc_cfg/unix_only/index.html \
 //  '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
 //  'Available on Unix only.'
-//@ matches - '//*[@class="item-name"]//*[@class="stab portability"]' '\AARM\Z'
+//@ matches - '//dt//*[@class="stab portability"]' '\AARM\Z'
 //@ count - '//*[@class="stab portability"]' 2
 #[doc(cfg(unix))]
 pub mod unix_only {
@@ -42,7 +42,7 @@ pub mod unix_only {
 //@ has doc_cfg/wasi_only/index.html \
 //  '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
 //  'Available on WASI only.'
-//@ matches - '//*[@class="item-name"]//*[@class="stab portability"]' '\AWebAssembly\Z'
+//@ matches - '//dt//*[@class="stab portability"]' '\AWebAssembly\Z'
 //@ count - '//*[@class="stab portability"]' 2
 #[doc(cfg(target_os = "wasi"))]
 pub mod wasi_only {
@@ -74,7 +74,7 @@ pub mod wasi_only {
 
 // the portability header is different on the module view versus the full view
 //@ has doc_cfg/index.html
-//@ matches - '//*[@class="item-name"]//*[@class="stab portability"]' '\Aavx\Z'
+//@ matches - '//dt//*[@class="stab portability"]' '\Aavx\Z'
 
 //@ has doc_cfg/fn.uses_target_feature.html
 //@ has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
diff --git a/tests/rustdoc/doc-hidden-reexports-109449.rs b/tests/rustdoc/doc-hidden-reexports-109449.rs
index cc3679f6196..8f195544120 100644
--- a/tests/rustdoc/doc-hidden-reexports-109449.rs
+++ b/tests/rustdoc/doc-hidden-reexports-109449.rs
@@ -26,7 +26,7 @@ pub mod single_reexport {
     //@ has 'foo/single_reexport/index.html'
 
     // First we check that we have 4 type aliases.
-    //@ count - '//*[@id="main-content"]/*[@class="item-table"]//code' 4
+    //@ count - '//*[@id="main-content"]/*[@class="item-table reexports"]//code' 4
 
     // Then we check that we have the correct link for each re-export.
 
@@ -131,10 +131,10 @@ mod private {
 pub mod doc_hidden_reexport {
     //@ has 'foo/doc_hidden_reexport/index.html'
     // Ensure there is only one item in this page and that it's a struct.
-    //@ count - '//*[@class="item-name"]' 1
+    //@ count - '//dt' 1
     //@ has - '//a[@class="struct"]' 'Reexport'
     // Check that the `#[doc(hidden)]` re-export's attributes are not taken into account.
-    //@ has - '//*[@class="desc docblock-short"]' 'Visible. Original.'
+    //@ has - '//dd' 'Visible. Original.'
     /// Visible.
     pub use self::Bar3 as Reexport;
     /// Hidden.
diff --git a/tests/rustdoc/double-hyphen-to-dash.rs b/tests/rustdoc/double-hyphen-to-dash.rs
index 009de4faf41..c14acd065cd 100644
--- a/tests/rustdoc/double-hyphen-to-dash.rs
+++ b/tests/rustdoc/double-hyphen-to-dash.rs
@@ -2,7 +2,7 @@
 
 #![crate_name = "foo"]
 
-//@ has 'foo/index.html' '//*[@class="desc docblock-short"]' '–'
+//@ has 'foo/index.html' '//dd' '–'
 //@ has 'foo/struct.Bar.html' '//*[@class="docblock"]' '–'
 
 /// --
diff --git a/tests/rustdoc/duplicate-cfg.rs b/tests/rustdoc/duplicate-cfg.rs
index 87c089e9735..93f26ab944d 100644
--- a/tests/rustdoc/duplicate-cfg.rs
+++ b/tests/rustdoc/duplicate-cfg.rs
@@ -2,8 +2,8 @@
 #![feature(doc_cfg)]
 
 //@ has 'foo/index.html'
-//@ matches '-' '//*[@class="item-name"]//*[@class="stab portability"]' '^sync$'
-//@ has '-' '//*[@class="item-name"]//*[@class="stab portability"]/@title' 'Available on crate feature `sync` only'
+//@ matches '-' '//dt//*[@class="stab portability"]' '^sync$'
+//@ has '-' '//dt//*[@class="stab portability"]/@title' 'Available on crate feature `sync` only'
 
 //@ has 'foo/struct.Foo.html'
 //@ has '-' '//*[@class="stab portability"]' 'sync'
diff --git a/tests/rustdoc/footnote-in-summary.rs b/tests/rustdoc/footnote-in-summary.rs
index d69282f1041..2a9668a9963 100644
--- a/tests/rustdoc/footnote-in-summary.rs
+++ b/tests/rustdoc/footnote-in-summary.rs
@@ -4,8 +4,8 @@
 #![crate_name = "foo"]
 
 //@ has 'foo/index.html'
-//@ has - '//*[@class="desc docblock-short"]' 'hello bla'
-//@ !has - '//*[@class="desc docblock-short"]/sup' '1'
+//@ has - '//dd' 'hello bla'
+//@ !has - '//dd/sup' '1'
 
 //@ has 'foo/struct.S.html'
 //@ has - '//*[@class="docblock"]//sup' '1'
diff --git a/tests/rustdoc/glob-reexport-attribute-merge-120487.rs b/tests/rustdoc/glob-reexport-attribute-merge-120487.rs
index 2fa10f546d5..5b918e0ffd9 100644
--- a/tests/rustdoc/glob-reexport-attribute-merge-120487.rs
+++ b/tests/rustdoc/glob-reexport-attribute-merge-120487.rs
@@ -7,9 +7,9 @@
 
 //@ has 'foo/index.html'
 // There are two items.
-//@ count - '//*[@class="item-table"]//div[@class="item-name"]' 2
+//@ count - '//*[@class="item-table"]/dt' 2
 // Only one of them should have an attribute.
-//@ count - '//*[@class="item-table"]//div[@class="item-name"]/*[@class="stab portability"]' 1
+//@ count - '//*[@class="item-table"]/dt/*[@class="stab portability"]' 1
 
 mod a {
     #[doc(cfg(not(feature = "a")))]
diff --git a/tests/rustdoc/glob-reexport-attribute-merge-doc-auto-cfg.rs b/tests/rustdoc/glob-reexport-attribute-merge-doc-auto-cfg.rs
index 314b457c2ad..d0a2165ec8a 100644
--- a/tests/rustdoc/glob-reexport-attribute-merge-doc-auto-cfg.rs
+++ b/tests/rustdoc/glob-reexport-attribute-merge-doc-auto-cfg.rs
@@ -6,9 +6,9 @@
 
 //@ has 'foo/index.html'
 // There are two items.
-//@ count - '//*[@class="item-table"]//div[@class="item-name"]' 2
+//@ count - '//*[@class="item-table"]/dt' 2
 // Only one of them should have an attribute.
-//@ count - '//*[@class="item-table"]//div[@class="item-name"]/*[@class="stab portability"]' 1
+//@ count - '//*[@class="item-table"]/dt/*[@class="stab portability"]' 1
 
 mod a {
     #[cfg(not(feature = "a"))]
diff --git a/tests/rustdoc/glob-shadowing-const.rs b/tests/rustdoc/glob-shadowing-const.rs
index 1eb5596cd9c..fbc22dbccaa 100644
--- a/tests/rustdoc/glob-shadowing-const.rs
+++ b/tests/rustdoc/glob-shadowing-const.rs
@@ -15,6 +15,6 @@ mod sub4 {
 pub use sub4::inner::*;
 
 //@ has 'foo/index.html'
-//@ has - '//div[@class="desc docblock-short"]' '1'
-//@ !has - '//div[@class="desc docblock-short"]' '0'
+//@ has - '//dd' '1'
+//@ !has - '//dd' '0'
 fn main() { assert_eq!(X, 1); }
diff --git a/tests/rustdoc/glob-shadowing.rs b/tests/rustdoc/glob-shadowing.rs
index a051bd407d5..d9e9ead3f9a 100644
--- a/tests/rustdoc/glob-shadowing.rs
+++ b/tests/rustdoc/glob-shadowing.rs
@@ -1,17 +1,17 @@
 //@ has 'glob_shadowing/index.html'
-//@ count - '//div[@class="item-name"]' 6
-//@ !has - '//div[@class="desc docblock-short"]' 'sub1::describe'
-//@ has - '//div[@class="desc docblock-short"]' 'sub2::describe'
+//@ count - '//dt' 6
+//@ !has - '//dd' 'sub1::describe'
+//@ has - '//dd' 'sub2::describe'
 
-//@ !has - '//div[@class="desc docblock-short"]' 'sub1::describe2'
+//@ !has - '//dd' 'sub1::describe2'
 
-//@ !has - '//div[@class="desc docblock-short"]' 'sub1::prelude'
-//@ has - '//div[@class="desc docblock-short"]' 'mod::prelude'
+//@ !has - '//dd' 'sub1::prelude'
+//@ has - '//dd' 'mod::prelude'
 
-//@ has - '//div[@class="desc docblock-short"]' 'sub1::Foo (struct)'
-//@ has - '//div[@class="desc docblock-short"]' 'mod::Foo (function)'
+//@ has - '//dd' 'sub1::Foo (struct)'
+//@ has - '//dd' 'mod::Foo (function)'
 
-//@ has - '//div[@class="desc docblock-short"]' 'sub4::inner::X'
+//@ has - '//dd' 'sub4::inner::X'
 
 //@ has 'glob_shadowing/fn.describe.html'
 //@ has - '//div[@class="docblock"]' 'sub2::describe'
diff --git a/tests/rustdoc/impl-on-ty-alias-issue-119015.rs b/tests/rustdoc/impl-on-ty-alias-issue-119015.rs
index cea0f5565a2..a514bc35bfc 100644
--- a/tests/rustdoc/impl-on-ty-alias-issue-119015.rs
+++ b/tests/rustdoc/impl-on-ty-alias-issue-119015.rs
@@ -2,8 +2,8 @@
 
 //@ has 'foo/index.html'
 // There should be only `type A`.
-//@ count - '//*[@class="item-table"]//*[@class="item-name"]' 1
-//@ has - '//*[@class="item-name"]/a[@href="type.A.html"]' 'A'
+//@ count - '//*[@class="item-table"]//dt' 1
+//@ has - '//dt/a[@href="type.A.html"]' 'A'
 
 mod foo {
     pub struct S;
diff --git a/tests/rustdoc/inline-private-with-intermediate-doc-hidden.rs b/tests/rustdoc/inline-private-with-intermediate-doc-hidden.rs
index 752f3843eea..d27ecbad169 100644
--- a/tests/rustdoc/inline-private-with-intermediate-doc-hidden.rs
+++ b/tests/rustdoc/inline-private-with-intermediate-doc-hidden.rs
@@ -9,7 +9,7 @@
 //@ count - '//*[@id="main-content"]/*[@class="section-header"]' 1
 //@ has - '//*[@id="main-content"]/*[@class="section-header"]' 'Structs'
 //@ has - '//*[@id="main-content"]//a[@href="struct.Reexport.html"]' 'Reexport'
-//@ has - '//*[@id="main-content"]//*[@class="desc docblock-short"]' 'Visible. Original.'
+//@ has - '//*[@id="main-content"]//dd' 'Visible. Original.'
 
 mod private {
     /// Original.
diff --git a/tests/rustdoc/inline_cross/inline_hidden.rs b/tests/rustdoc/inline_cross/inline_hidden.rs
index 095cd2d3c55..49ca2db6a22 100644
--- a/tests/rustdoc/inline_cross/inline_hidden.rs
+++ b/tests/rustdoc/inline_cross/inline_hidden.rs
@@ -11,14 +11,14 @@ extern crate rustdoc_hidden;
 pub use rustdoc_hidden::Foo;
 
 // Even if the foreign item has `doc(hidden)`, we should be able to inline it.
-//@ has - '//*[@class="item-name"]/a[@class="struct"]' 'Inlined'
+//@ has - '//dt/a[@class="struct"]' 'Inlined'
 #[doc(inline)]
 pub use rustdoc_hidden::Foo as Inlined;
 
 // Even with this import, we should not see `Foo`.
-//@ count - '//*[@class="item-name"]' 4
-//@ has - '//*[@class="item-name"]/a[@class="struct"]' 'Bar'
-//@ has - '//*[@class="item-name"]/a[@class="fn"]' 'foo'
+//@ count - '//dt' 4
+//@ has - '//dt/a[@class="struct"]' 'Bar'
+//@ has - '//dt/a[@class="fn"]' 'foo'
 pub use rustdoc_hidden::*;
 
 //@ has inline_hidden/fn.foo.html
diff --git a/tests/rustdoc/inline_cross/macros.rs b/tests/rustdoc/inline_cross/macros.rs
index aab7a3650b1..57eec77899e 100644
--- a/tests/rustdoc/inline_cross/macros.rs
+++ b/tests/rustdoc/inline_cross/macros.rs
@@ -6,10 +6,8 @@
 
 extern crate macros;
 
-//@ has foo/index.html '//*[@class="item-name"]/span[@class="stab deprecated"]' \
-//         Deprecated
-//@ has - '//*[@class="item-name"]/span[@class="stab unstable"]' \
-//         Experimental
+//@ has foo/index.html '//dt/span[@class="stab deprecated"]' Deprecated
+//@ has - '//dt/span[@class="stab unstable"]' Experimental
 
 //@ has foo/macro.my_macro.html
 //@ has - '//*[@class="docblock"]' 'docs for my_macro'
diff --git a/tests/rustdoc/internal.rs b/tests/rustdoc/internal.rs
index e0bccefda1d..244e9138f2b 100644
--- a/tests/rustdoc/internal.rs
+++ b/tests/rustdoc/internal.rs
@@ -8,7 +8,7 @@
 //@ !matches internal/index.html \
 //      '//*[@class="desc docblock-short"]/span[@class="stab internal"]' \
 //      ''
-//@ matches - '//*[@class="desc docblock-short"]' 'Docs'
+//@ matches - '//dd' 'Docs'
 
 //@ !has internal/struct.S.html '//*[@class="stab unstable"]' ''
 //@ !has internal/struct.S.html '//*[@class="stab internal"]' ''
diff --git a/tests/rustdoc/intra-doc/module-scope-name-resolution-55364.rs b/tests/rustdoc/intra-doc/module-scope-name-resolution-55364.rs
index 06cb764423e..f0362f684ad 100644
--- a/tests/rustdoc/intra-doc/module-scope-name-resolution-55364.rs
+++ b/tests/rustdoc/intra-doc/module-scope-name-resolution-55364.rs
@@ -32,8 +32,8 @@ pub mod subone {
 //@ has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="../fn.foo.html"]' 'foo'
 //@ has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="../fn.bar.html"]' 'bar'
 // Though there should be such links later
-//@ has - '//section[@id="main-content"]/ul[@class="item-table"]//div[@class="item-name"]/a[@class="fn"][@href="fn.foo.html"]' 'foo'
-//@ has - '//section[@id="main-content"]/ul[@class="item-table"]//div[@class="item-name"]/a[@class="fn"][@href="fn.bar.html"]' 'bar'
+//@ has - '//section[@id="main-content"]/dl[@class="item-table"]/dt/a[@class="fn"][@href="fn.foo.html"]' 'foo'
+//@ has - '//section[@id="main-content"]/dl[@class="item-table"]/dt/a[@class="fn"][@href="fn.bar.html"]' 'bar'
 /// See either [foo] or [bar].
 pub mod subtwo {
 
@@ -71,8 +71,8 @@ pub mod subthree {
 // Next we go *deeper* - In order to ensure it's not just "this or parent"
 // we test `crate::` and a `super::super::...` chain
 //@ has foo/subfour/subfive/subsix/subseven/subeight/index.html
-//@ has - '//section[@id="main-content"]/ul[@class="item-table"]//div[@class="desc docblock-short"]//a[@href="../../../../../subone/fn.foo.html"]' 'other foo'
-//@ has - '//section[@id="main-content"]/ul[@class="item-table"]//div[@class="desc docblock-short"]//a[@href="../../../../../subtwo/fn.bar.html"]' 'other bar'
+//@ has - '//section[@id="main-content"]/dl[@class="item-table"]/dd//a[@href="../../../../../subone/fn.foo.html"]' 'other foo'
+//@ has - '//section[@id="main-content"]/dl[@class="item-table"]/dd//a[@href="../../../../../subtwo/fn.bar.html"]' 'other bar'
 pub mod subfour {
     pub mod subfive {
         pub mod subsix {
diff --git a/tests/rustdoc/item-desc-list-at-start.item-table.html b/tests/rustdoc/item-desc-list-at-start.item-table.html
index cff4f816529..89b4ac640f2 100644
--- a/tests/rustdoc/item-desc-list-at-start.item-table.html
+++ b/tests/rustdoc/item-desc-list-at-start.item-table.html
@@ -1 +1 @@
-<ul class="item-table"><li><div class="item-name"><a class="constant" href="constant.MY_CONSTANT.html" title="constant item_desc_list_at_start::MY_CONSTANT">MY_<wbr />CONSTANT</a></div><div class="desc docblock-short">Groups: <code>SamplePatternSGIS</code>, <code>SamplePatternEXT</code></div></li></ul>
\ No newline at end of file
+<dl class="item-table"><dt><a class="constant" href="constant.MY_CONSTANT.html" title="constant item_desc_list_at_start::MY_CONSTANT">MY_<wbr />CONSTANT</a></dt><dd>Groups: <code>SamplePatternSGIS</code>, <code>SamplePatternEXT</code></dd></dl>
\ No newline at end of file
diff --git a/tests/rustdoc/item-desc-list-at-start.rs b/tests/rustdoc/item-desc-list-at-start.rs
index fbcc36066f1..7c2b31c9460 100644
--- a/tests/rustdoc/item-desc-list-at-start.rs
+++ b/tests/rustdoc/item-desc-list-at-start.rs
@@ -1,7 +1,8 @@
 //@ has item_desc_list_at_start/index.html
-//@ count - '//ul[@class="item-table"]/li/div/li' 0
-//@ count - '//ul[@class="item-table"]/li' 1
-//@ snapshot item-table - '//ul[@class="item-table"]'
+//@ count - '//dl[@class="item-table"]/dd//ul' 0
+//@ count - '//dl[@class="item-table"]/dd//li' 0
+//@ count - '//dl[@class="item-table"]/dd' 1
+//@ snapshot item-table - '//dl[@class="item-table"]'
 
 // based on https://docs.rs/gl_constants/0.1.1/src/gl_constants/lib.rs.html#16
 
diff --git a/tests/rustdoc/macro-rules-broken-intra-doc-106142.rs b/tests/rustdoc/macro-rules-broken-intra-doc-106142.rs
deleted file mode 100644
index 0d146a3c5cd..00000000000
--- a/tests/rustdoc/macro-rules-broken-intra-doc-106142.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-// https://github.com/rust-lang/rust/issues/106142
-#![crate_name="foo"]
-
-//@ has 'foo/a/index.html'
-//@ count 'foo/a/index.html' '//ul[@class="item-table"]//li//a' 1
-
-#![allow(rustdoc::broken_intra_doc_links)]
-
-pub mod a {
-    /// [`m`]
-    pub fn f() {}
-
-    #[macro_export]
-    macro_rules! m {
-        () => {};
-    }
-}
diff --git a/tests/rustdoc/multiple-mods-w-same-name-doc-inline-83375.rs b/tests/rustdoc/multiple-mods-w-same-name-doc-inline-83375.rs
index 6d255ed6004..be32fcc7e4a 100644
--- a/tests/rustdoc/multiple-mods-w-same-name-doc-inline-83375.rs
+++ b/tests/rustdoc/multiple-mods-w-same-name-doc-inline-83375.rs
@@ -10,7 +10,7 @@ pub mod sub {
 }
 
 //@ count foo/index.html '//a[@class="mod"][@title="mod foo::prelude"]' 1
-//@ count foo/prelude/index.html '//div[@class="item-row"]' 0
+//@ count foo/prelude/index.html '//ul[@class="item-table"]' 0
 pub mod prelude {}
 
 #[doc(inline)]
diff --git a/tests/rustdoc/multiple-mods-w-same-name-doc-inline-last-item-83375.rs b/tests/rustdoc/multiple-mods-w-same-name-doc-inline-last-item-83375.rs
index a59b48232a3..4b3b467382b 100644
--- a/tests/rustdoc/multiple-mods-w-same-name-doc-inline-last-item-83375.rs
+++ b/tests/rustdoc/multiple-mods-w-same-name-doc-inline-last-item-83375.rs
@@ -13,5 +13,5 @@ pub mod sub {
 pub use sub::*;
 
 //@ count foo/index.html '//a[@class="mod"][@title="mod foo::prelude"]' 1
-//@ count foo/prelude/index.html '//div[@class="item-row"]' 0
+//@ count foo/prelude/index.html '//ul[@class="item-table"]' 0
 pub mod prelude {}
diff --git a/tests/rustdoc/nested-items-issue-111415.rs b/tests/rustdoc/nested-items-issue-111415.rs
index a5cd3ca0b1a..79dc2b0378f 100644
--- a/tests/rustdoc/nested-items-issue-111415.rs
+++ b/tests/rustdoc/nested-items-issue-111415.rs
@@ -10,7 +10,7 @@
 //@ has - '//*[@id="main-content"]/*[@class="section-header"]' 'Functions'
 //@ has - '//*[@id="main-content"]/*[@class="section-header"]' 'Traits'
 // Checking that there are only three items.
-//@ count - '//*[@id="main-content"]//*[@class="item-name"]' 3
+//@ count - '//*[@id="main-content"]//dt' 3
 //@ has - '//*[@id="main-content"]//a[@href="struct.Bar.html"]' 'Bar'
 //@ has - '//*[@id="main-content"]//a[@href="fn.foo.html"]' 'foo'
 //@ has - '//*[@id="main-content"]//a[@href="trait.Foo.html"]' 'Foo'
diff --git a/tests/rustdoc/overlapping-reexport-105735-2.rs b/tests/rustdoc/overlapping-reexport-105735-2.rs
index 9f823ec5923..fa43924ff4e 100644
--- a/tests/rustdoc/overlapping-reexport-105735-2.rs
+++ b/tests/rustdoc/overlapping-reexport-105735-2.rs
@@ -5,8 +5,8 @@
 #![no_std]
 
 //@ has 'foo/index.html'
-//@ has - '//*[@class="item-name"]/a[@class="type"]' 'AtomicU8'
-//@ has - '//*[@class="item-name"]/a[@class="constant"]' 'AtomicU8'
+//@ has - '//dt/a[@class="type"]' 'AtomicU8'
+//@ has - '//dt/a[@class="constant"]' 'AtomicU8'
 // We also ensure we don't have another item displayed.
 //@ count - '//*[@id="main-content"]/*[@class="section-header"]' 2
 //@ has - '//*[@id="main-content"]/*[@class="section-header"]' 'Type Aliases'
diff --git a/tests/rustdoc/overlapping-reexport-105735.rs b/tests/rustdoc/overlapping-reexport-105735.rs
index 2a2d0fa9830..d1b5c0b6749 100644
--- a/tests/rustdoc/overlapping-reexport-105735.rs
+++ b/tests/rustdoc/overlapping-reexport-105735.rs
@@ -5,8 +5,8 @@
 #![no_std]
 
 //@ has 'foo/index.html'
-//@ has - '//*[@class="item-name"]/a[@class="struct"]' 'AtomicU8'
-//@ has - '//*[@class="item-name"]/a[@class="constant"]' 'AtomicU8'
+//@ has - '//dt/a[@class="struct"]' 'AtomicU8'
+//@ has - '//dt/a[@class="constant"]' 'AtomicU8'
 // We also ensure we don't have another item displayed.
 //@ count - '//*[@id="main-content"]/*[@class="section-header"]' 2
 //@ has - '//*[@id="main-content"]/*[@class="section-header"]' 'Structs'
diff --git a/tests/rustdoc/pub-use-root-path-95873.rs b/tests/rustdoc/pub-use-root-path-95873.rs
index e3d5ee6e315..8e4fd9e8d50 100644
--- a/tests/rustdoc/pub-use-root-path-95873.rs
+++ b/tests/rustdoc/pub-use-root-path-95873.rs
@@ -1,5 +1,5 @@
 // https://github.com/rust-lang/rust/issues/95873
 #![crate_name = "foo"]
 
-//@ has foo/index.html "//*[@class='item-name']" "pub use ::std as x;"
+//@ has foo/index.html "//dt" "pub use ::std as x;"
 pub use ::std as x;
diff --git a/tests/rustdoc/reexport-cfg.rs b/tests/rustdoc/reexport-cfg.rs
index 7270da3d678..73b66824316 100644
--- a/tests/rustdoc/reexport-cfg.rs
+++ b/tests/rustdoc/reexport-cfg.rs
@@ -13,18 +13,18 @@ mod foo {
 }
 
 //@ has 'foo/index.html'
-//@ has - '//*[@class="item-name"]' 'BabarNon-lie'
+//@ has - '//dt' 'BabarNon-lie'
 #[cfg(not(feature = "lie"))]
 pub use crate::foo::Bar as Babar;
 
-//@ has - '//*[@class="item-name"]' 'Babar2Non-cake'
+//@ has - '//dt' 'Babar2Non-cake'
 #[doc(cfg(not(feature = "cake")))]
 pub use crate::foo::Bar2 as Babar2;
 
-//@ has - '//*[@class="item-table"]/li' 'pub use crate::Babar as Elephant;Non-robot'
+//@ has - '//*[@class="item-table reexports"]/dt' 'pub use crate::Babar as Elephant;Non-robot'
 #[cfg(not(feature = "robot"))]
 pub use crate::Babar as Elephant;
 
-//@ has - '//*[@class="item-table"]/li' 'pub use crate::Babar2 as Elephant2;Non-cat'
+//@ has - '//*[@class="item-table reexports"]/dt' 'pub use crate::Babar2 as Elephant2;Non-cat'
 #[doc(cfg(not(feature = "cat")))]
 pub use crate::Babar2 as Elephant2;
diff --git a/tests/rustdoc/reexport-check.rs b/tests/rustdoc/reexport-check.rs
index 0f4e203d1d3..fc10e3aadd0 100644
--- a/tests/rustdoc/reexport-check.rs
+++ b/tests/rustdoc/reexport-check.rs
@@ -8,13 +8,13 @@ extern crate reexport_check;
 #[allow(deprecated, deprecated_in_future)]
 pub use std::i32;
 //@ !has 'foo/index.html' '//code' 'pub use self::string::String;'
-//@ has 'foo/index.html' '//div[@class="item-name"]' 'String'
+//@ has 'foo/index.html' '//dt' 'String'
 pub use std::string::String;
 
 // i32 is deprecated, String is not
 //@ count 'foo/index.html' '//span[@class="stab deprecated"]' 1
 
-//@ has 'foo/index.html' '//div[@class="desc docblock-short"]' 'Docs in original'
+//@ has 'foo/index.html' '//dd' 'Docs in original'
 // this is a no-op, but shows what happens if there's an attribute that isn't a doc-comment
 #[doc(inline)]
 pub use reexport_check::S;
diff --git a/tests/rustdoc/reexport-doc-hidden-inside-private.rs b/tests/rustdoc/reexport-doc-hidden-inside-private.rs
index fac928fc2a3..8e194ef74fb 100644
--- a/tests/rustdoc/reexport-doc-hidden-inside-private.rs
+++ b/tests/rustdoc/reexport-doc-hidden-inside-private.rs
@@ -12,5 +12,5 @@ mod private_module {
 //@ has - '//*[@id="reexport.Foo"]/code' 'pub use crate::private_module::Public as Foo;'
 pub use crate::private_module::Public as Foo;
 // Glob re-exports with no visible items should not be displayed.
-//@ count - '//*[@class="item-table"]/li' 1
+//@ count - '//*[@class="item-table reexports"]/dt' 1
 pub use crate::private_module::*;
diff --git a/tests/rustdoc/reexport-of-reexport-108679.rs b/tests/rustdoc/reexport-of-reexport-108679.rs
index 5c1b4bcbd83..0d2faf71d32 100644
--- a/tests/rustdoc/reexport-of-reexport-108679.rs
+++ b/tests/rustdoc/reexport-of-reexport-108679.rs
@@ -25,5 +25,6 @@ pub mod a {
 //@ has - '//*[@id="main-content"]//*[@id="reexport.A"]' 'pub use self::a::A;'
 //@ has - '//*[@id="main-content"]//*[@id="reexport.B"]' 'pub use self::a::B;'
 // Should only contain "Modules" and "Re-exports".
-//@ count - '//*[@id="main-content"]//*[@class="item-table"]' 2
+//@ count - '//*[@id="main-content"]//*[@class="item-table"]' 1
+//@ count - '//*[@id="main-content"]//*[@class="item-table reexports"]' 1
 pub use self::a::{A, B};
diff --git a/tests/rustdoc/reexport-trait-from-hidden-111064.rs b/tests/rustdoc/reexport-trait-from-hidden-111064.rs
index 84ec818ef33..8b9ad7616ea 100644
--- a/tests/rustdoc/reexport-trait-from-hidden-111064.rs
+++ b/tests/rustdoc/reexport-trait-from-hidden-111064.rs
@@ -5,7 +5,7 @@
 #![crate_name = "foo"]
 
 //@ has 'foo/index.html'
-//@ has - '//*[@id="main-content"]//*[@class="item-name"]/a[@href="trait.Foo.html"]' 'Foo'
+//@ has - '//*[@id="main-content"]//dt/a[@href="trait.Foo.html"]' 'Foo'
 
 //@ has 'foo/trait.Foo.html'
 //@ has - '//*[@id="main-content"]//*[@class="code-header"]' 'fn test()'
diff --git a/tests/rustdoc/short-docblock.rs b/tests/rustdoc/short-docblock.rs
index c80a5025ebe..fa0af85696a 100644
--- a/tests/rustdoc/short-docblock.rs
+++ b/tests/rustdoc/short-docblock.rs
@@ -1,7 +1,7 @@
 #![crate_name = "foo"]
 
-//@ has foo/index.html '//*[@class="desc docblock-short"]' 'fooo'
-//@ !has foo/index.html '//*[@class="desc docblock-short"]/h1' 'fooo'
+//@ has foo/index.html '//dd' 'fooo'
+//@ !has foo/index.html '//dd//h1' 'fooo'
 
 //@ has foo/fn.foo.html '//h2[@id="fooo"]' 'fooo'
 //@ has foo/fn.foo.html '//h2[@id="fooo"]/a[@href="#fooo"]' '§'
@@ -10,8 +10,8 @@
 /// foo
 pub fn foo() {}
 
-//@ has foo/index.html '//*[@class="desc docblock-short"]' 'mooood'
-//@ !has foo/index.html '//*[@class="desc docblock-short"]/h2' 'mooood'
+//@ has foo/index.html '//dd' 'mooood'
+//@ !has foo/index.html '//dd//h2' 'mooood'
 
 //@ has foo/foo/index.html '//h3[@id="mooood"]' 'mooood'
 //@ has foo/foo/index.html '//h3[@id="mooood"]/a[@href="#mooood"]' '§'
@@ -20,8 +20,7 @@ pub fn foo() {}
 /// foo mod
 pub mod foo {}
 
-//@ has foo/index.html '//*[@class="desc docblock-short"]/a[@href=\
-//                      "https://nougat.world"]/code' 'nougat'
+//@ has foo/index.html '//dd/a[@href="https://nougat.world"]/code' 'nougat'
 
 /// [`nougat`](https://nougat.world)
 pub struct Bar;
diff --git a/tests/rustdoc/sidebar/sidebar-items.rs b/tests/rustdoc/sidebar/sidebar-items.rs
index 57c2eee91a9..6e13457796e 100644
--- a/tests/rustdoc/sidebar/sidebar-items.rs
+++ b/tests/rustdoc/sidebar/sidebar-items.rs
@@ -26,7 +26,7 @@ pub trait Foo {
 }
 
 //@ has foo/trait.DynCompatible.html
-//@ !has - '//div[@class="sidebar-elems"]//h3/a[@href="#object-safety"]' ''
+//@ !has - '//div[@class="sidebar-elems"]//h3/a[@href="#dyn-compatibility"]' ''
 pub trait DynCompatible {
     fn access(&self);
 }
diff --git a/tests/rustdoc/stability.rs b/tests/rustdoc/stability.rs
index 550eb0bc137..b74abb0e0ba 100644
--- a/tests/rustdoc/stability.rs
+++ b/tests/rustdoc/stability.rs
@@ -5,9 +5,9 @@
 #![stable(feature = "core", since = "1.6.0")]
 
 //@ has stability/index.html
-//@ has - '//ul[@class="item-table"]/li[1]//a' AaStable
-//@ has - '//ul[@class="item-table"]/li[2]//a' ZzStable
-//@ has - '//ul[@class="item-table"]/li[3]//a' Unstable
+//@ has - '//dl[@class="item-table"]/dt[1]//a' AaStable
+//@ has - '//dl[@class="item-table"]/dt[2]//a' ZzStable
+//@ has - '//dl[@class="item-table"]/dt[3]//a' Unstable
 
 #[stable(feature = "rust2", since = "2.2.2")]
 pub struct AaStable;
diff --git a/tests/rustdoc/staged-api-deprecated-unstable-32374.rs b/tests/rustdoc/staged-api-deprecated-unstable-32374.rs
index 556b6fb61ac..1021ce86df0 100644
--- a/tests/rustdoc/staged-api-deprecated-unstable-32374.rs
+++ b/tests/rustdoc/staged-api-deprecated-unstable-32374.rs
@@ -4,11 +4,9 @@
 #![unstable(feature = "test", issue = "32374")]
 #![crate_name="issue_32374"]
 
-//@ matches issue_32374/index.html '//*[@class="item-name"]/span[@class="stab deprecated"]' \
-//      'Deprecated'
-//@ matches issue_32374/index.html '//*[@class="item-name"]/span[@class="stab unstable"]' \
-//      'Experimental'
-//@ matches issue_32374/index.html '//*[@class="desc docblock-short"]/text()' 'Docs'
+//@ matches issue_32374/index.html '//dt/span[@class="stab deprecated"]' 'Deprecated'
+//@ matches issue_32374/index.html '//dt/span[@class="stab unstable"]' 'Experimental'
+//@ matches issue_32374/index.html '//dd/text()' 'Docs'
 
 //@ has issue_32374/struct.T.html '//*[@class="stab deprecated"]/span' '👎'
 //@ has issue_32374/struct.T.html '//*[@class="stab deprecated"]/span' \
diff --git a/tests/rustdoc/summary-header-46377.rs b/tests/rustdoc/summary-header-46377.rs
index 11445f0dad6..c84f3a65cfb 100644
--- a/tests/rustdoc/summary-header-46377.rs
+++ b/tests/rustdoc/summary-header-46377.rs
@@ -1,6 +1,6 @@
 // https://github.com/rust-lang/rust/issues/46377
 #![crate_name="foo"]
 
-//@ has 'foo/index.html' '//*[@class="desc docblock-short"]' 'Check out this struct!'
+//@ has 'foo/index.html' '//dd' 'Check out this struct!'
 /// # Check out this struct!
 pub struct SomeStruct;
diff --git a/tests/ui-fulldeps/compiler-calls.rs b/tests/ui-fulldeps/compiler-calls.rs
index 5fb47c87e50..d6148dfec43 100644
--- a/tests/ui-fulldeps/compiler-calls.rs
+++ b/tests/ui-fulldeps/compiler-calls.rs
@@ -25,7 +25,7 @@ fn main() {
     let mut count = 1;
     let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()];
     rustc_driver::catch_fatal_errors(|| -> interface::Result<()> {
-        rustc_driver::RunCompiler::new(&args, &mut TestCalls { count: &mut count }).run();
+        rustc_driver::run_compiler(&args, &mut TestCalls { count: &mut count });
         Ok(())
     })
     .ok();
diff --git a/tests/ui-fulldeps/obtain-borrowck.rs b/tests/ui-fulldeps/obtain-borrowck.rs
index 8ea2ac61971..f8064c245a8 100644
--- a/tests/ui-fulldeps/obtain-borrowck.rs
+++ b/tests/ui-fulldeps/obtain-borrowck.rs
@@ -47,7 +47,7 @@ fn main() {
         rustc_args.push("-Zpolonius".to_owned());
         let mut callbacks = CompilerCalls::default();
         // Call the Rust compiler with our callbacks.
-        rustc_driver::RunCompiler::new(&rustc_args, &mut callbacks).run();
+        rustc_driver::run_compiler(&rustc_args, &mut callbacks);
         Ok(())
     });
     std::process::exit(exit_code);
diff --git a/tests/ui-fulldeps/run-compiler-twice.rs b/tests/ui-fulldeps/run-compiler-twice.rs
index bcc235e58ed..f414c961627 100644
--- a/tests/ui-fulldeps/run-compiler-twice.rs
+++ b/tests/ui-fulldeps/run-compiler-twice.rs
@@ -72,7 +72,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf, linker: Option<&Path
         override_queries: None,
         make_codegen_backend: None,
         registry: rustc_driver::diagnostics_registry(),
-        using_internal_features: std::sync::Arc::default(),
+        using_internal_features: &rustc_driver::USING_INTERNAL_FEATURES,
         expanded_args: Default::default(),
     };
 
diff --git a/tests/ui/array-slice-vec/vec-macro-no-std.rs b/tests/ui/array-slice-vec/vec-macro-no-std.rs
index 1b5ab536dcb..ea0df0bea71 100644
--- a/tests/ui/array-slice-vec/vec-macro-no-std.rs
+++ b/tests/ui/array-slice-vec/vec-macro-no-std.rs
@@ -1,21 +1,21 @@
 //@ run-pass
-
 //@ ignore-emscripten no no_std executables
+//@ ignore-wasm different `main` convention
 
-#![feature(lang_items, start, rustc_private)]
 #![no_std]
+#![no_main]
 
+// Import global allocator and panic handler.
 extern crate std as other;
 
-#[macro_use]
-extern crate alloc;
+#[macro_use] extern crate alloc;
 
 use alloc::vec::Vec;
 
 // Issue #16806
 
-#[start]
-fn start(_argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int {
     let x: Vec<u8> = vec![0, 1, 2];
     match x.last() {
         Some(&2) => (),
diff --git a/tests/ui/associated-consts/associated-const-in-trait.rs b/tests/ui/associated-consts/associated-const-in-trait.rs
index 4e8143d5795..90ad596b23e 100644
--- a/tests/ui/associated-consts/associated-const-in-trait.rs
+++ b/tests/ui/associated-consts/associated-const-in-trait.rs
@@ -5,9 +5,9 @@ trait Trait {
 }
 
 impl dyn Trait {
-    //~^ ERROR the trait `Trait` cannot be made into an object [E0038]
+    //~^ ERROR the trait `Trait` is not dyn compatible [E0038]
     const fn n() -> usize { Self::N }
-    //~^ ERROR the trait `Trait` cannot be made into an object [E0038]
+    //~^ ERROR the trait `Trait` is not dyn compatible [E0038]
 }
 
 fn main() {}
diff --git a/tests/ui/associated-consts/associated-const-in-trait.stderr b/tests/ui/associated-consts/associated-const-in-trait.stderr
index b40c1005797..107ceeaf113 100644
--- a/tests/ui/associated-consts/associated-const-in-trait.stderr
+++ b/tests/ui/associated-consts/associated-const-in-trait.stderr
@@ -1,29 +1,31 @@
-error[E0038]: the trait `Trait` cannot be made into an object
+error[E0038]: the trait `Trait` is not dyn compatible
   --> $DIR/associated-const-in-trait.rs:7:6
    |
 LL | impl dyn Trait {
-   |      ^^^^^^^^^ `Trait` cannot be made into an object
+   |      ^^^^^^^^^ `Trait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/associated-const-in-trait.rs:4:11
    |
 LL | trait Trait {
-   |       ----- this trait cannot be made into an object...
+   |       ----- this trait is not dyn compatible...
 LL |     const N: usize;
    |           ^ ...because it contains this associated `const`
    = help: consider moving `N` to another trait
 
-error[E0038]: the trait `Trait` cannot be made into an object
+error[E0038]: the trait `Trait` is not dyn compatible
   --> $DIR/associated-const-in-trait.rs:9:29
    |
 LL |     const fn n() -> usize { Self::N }
-   |                             ^^^^ `Trait` cannot be made into an object
+   |                             ^^^^ `Trait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/associated-const-in-trait.rs:4:11
    |
 LL | trait Trait {
-   |       ----- this trait cannot be made into an object...
+   |       ----- this trait is not dyn compatible...
 LL |     const N: usize;
    |           ^ ...because it contains this associated `const`
    = help: consider moving `N` to another trait
diff --git a/tests/ui/associated-item/issue-48027.rs b/tests/ui/associated-item/issue-48027.rs
index d2b51184c99..715f3935107 100644
--- a/tests/ui/associated-item/issue-48027.rs
+++ b/tests/ui/associated-item/issue-48027.rs
@@ -3,6 +3,6 @@ trait Bar {
     fn return_n(&self) -> [u8; Bar::X]; //~ ERROR: E0790
 }
 
-impl dyn Bar {} //~ ERROR: the trait `Bar` cannot be made into an object
+impl dyn Bar {} //~ ERROR: the trait `Bar` is not dyn compatible
 
 fn main() {}
diff --git a/tests/ui/associated-item/issue-48027.stderr b/tests/ui/associated-item/issue-48027.stderr
index 2883259ce2f..1baaefd7720 100644
--- a/tests/ui/associated-item/issue-48027.stderr
+++ b/tests/ui/associated-item/issue-48027.stderr
@@ -1,14 +1,15 @@
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/issue-48027.rs:6:6
    |
 LL | impl dyn Bar {}
-   |      ^^^^^^^ `Bar` cannot be made into an object
+   |      ^^^^^^^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-48027.rs:2:11
    |
 LL | trait Bar {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     const X: usize;
    |           ^ ...because it contains this associated `const`
    = help: consider moving `X` to another trait
diff --git a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr
index c5260adbed4..88db3611719 100644
--- a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr
+++ b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr
@@ -40,14 +40,14 @@ LL | type X = std::ops::Deref::Target;
    |
 help: use fully-qualified syntax
    |
+LL | type X = <ByteStr as Deref>::Target;
+   |          ~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | type X = <ByteString as Deref>::Target;
+   |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 LL | type X = <CString as Deref>::Target;
    |          ~~~~~~~~~~~~~~~~~~~~~~~~~~
 LL | type X = <IoSlice<'_> as Deref>::Target;
    |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-LL | type X = <IoSliceMut<'_> as Deref>::Target;
-   |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-LL | type X = <OsString as Deref>::Target;
-   |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~
      and N other candidates
 
 error: aborting due to 5 previous errors
diff --git a/tests/ui/async-await/async-closures/is-not-fn.stderr b/tests/ui/async-await/async-closures/is-not-fn.current.stderr
index bc1d5e6e9d1..e7be1d5b10e 100644
--- a/tests/ui/async-await/async-closures/is-not-fn.stderr
+++ b/tests/ui/async-await/async-closures/is-not-fn.current.stderr
@@ -1,5 +1,5 @@
-error[E0271]: expected `{async closure@is-not-fn.rs:5:14}` to be a closure that returns `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:5:23: 5:25}`
-  --> $DIR/is-not-fn.rs:5:14
+error[E0271]: expected `{async closure@is-not-fn.rs:8:14}` to be a closure that returns `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}`
+  --> $DIR/is-not-fn.rs:8:14
    |
 LL |     needs_fn(async || {});
    |     -------- ^^^^^^^^^^^ expected `()`, found `async` closure body
@@ -7,9 +7,9 @@ LL |     needs_fn(async || {});
    |     required by a bound introduced by this call
    |
    = note:         expected unit type `()`
-           found `async` closure body `{async closure body@$DIR/is-not-fn.rs:5:23: 5:25}`
+           found `async` closure body `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}`
 note: required by a bound in `needs_fn`
-  --> $DIR/is-not-fn.rs:4:25
+  --> $DIR/is-not-fn.rs:7:25
    |
 LL |     fn needs_fn(x: impl FnOnce()) {}
    |                         ^^^^^^^^ required by this bound in `needs_fn`
diff --git a/tests/ui/async-await/async-closures/is-not-fn.next.stderr b/tests/ui/async-await/async-closures/is-not-fn.next.stderr
new file mode 100644
index 00000000000..e7be1d5b10e
--- /dev/null
+++ b/tests/ui/async-await/async-closures/is-not-fn.next.stderr
@@ -0,0 +1,19 @@
+error[E0271]: expected `{async closure@is-not-fn.rs:8:14}` to be a closure that returns `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}`
+  --> $DIR/is-not-fn.rs:8:14
+   |
+LL |     needs_fn(async || {});
+   |     -------- ^^^^^^^^^^^ expected `()`, found `async` closure body
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = note:         expected unit type `()`
+           found `async` closure body `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}`
+note: required by a bound in `needs_fn`
+  --> $DIR/is-not-fn.rs:7:25
+   |
+LL |     fn needs_fn(x: impl FnOnce()) {}
+   |                         ^^^^^^^^ required by this bound in `needs_fn`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/async-await/async-closures/is-not-fn.rs b/tests/ui/async-await/async-closures/is-not-fn.rs
index 4acaa5d9809..eacd07b7cdd 100644
--- a/tests/ui/async-await/async-closures/is-not-fn.rs
+++ b/tests/ui/async-await/async-closures/is-not-fn.rs
@@ -1,7 +1,10 @@
 //@ edition:2021
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
 
 fn main() {
     fn needs_fn(x: impl FnOnce()) {}
     needs_fn(async || {});
-    //~^ ERROR expected `{async closure@is-not-fn.rs:5:14}` to be a closure that returns `()`
+    //~^ ERROR expected `{async closure@is-not-fn.rs:8:14}` to be a closure that returns `()`
 }
diff --git a/tests/ui/async-await/async-fn/dyn-pos.rs b/tests/ui/async-await/async-fn/dyn-pos.rs
index d71af1bd53e..ab4685b07bb 100644
--- a/tests/ui/async-await/async-fn/dyn-pos.rs
+++ b/tests/ui/async-await/async-fn/dyn-pos.rs
@@ -1,6 +1,6 @@
 //@ edition:2018
 
 fn foo(x: &dyn AsyncFn()) {}
-//~^ ERROR the trait `AsyncFnMut` cannot be made into an object
+//~^ ERROR the trait `AsyncFnMut` is not dyn compatible
 
 fn main() {}
diff --git a/tests/ui/async-await/async-fn/dyn-pos.stderr b/tests/ui/async-await/async-fn/dyn-pos.stderr
index 0c901846671..f9d2a669477 100644
--- a/tests/ui/async-await/async-fn/dyn-pos.stderr
+++ b/tests/ui/async-await/async-fn/dyn-pos.stderr
@@ -1,17 +1,14 @@
-error[E0038]: the trait `AsyncFnMut` cannot be made into an object
+error[E0038]: the trait `AsyncFnMut` is not dyn compatible
   --> $DIR/dyn-pos.rs:3:16
    |
 LL | fn foo(x: &dyn AsyncFn()) {}
-   |                ^^^^^^^^^ `AsyncFnMut` cannot be made into an object
+   |                ^^^^^^^^^ `AsyncFnMut` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL
    |
-   = note: the trait cannot be made into an object because it contains the generic associated type `CallRefFuture`
-   = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `AsyncFnMut` for this new enum and using it instead:
-             &F
-             &mut F
-             std::boxed::Box<F, A>
+   = note: the trait is not dyn compatible because it contains the generic associated type `CallRefFuture`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/async-await/coroutine-desc.stderr b/tests/ui/async-await/coroutine-desc.stderr
index 01482a9cb1f..84a1a3166ad 100644
--- a/tests/ui/async-await/coroutine-desc.stderr
+++ b/tests/ui/async-await/coroutine-desc.stderr
@@ -30,7 +30,6 @@ LL |     fun(one(), two());
    |     |   expected all arguments to be this future type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
-   = help: consider `await`ing on both `Future`s
    = note: distinct uses of `impl Trait` result in different opaque types
 note: function defined here
   --> $DIR/coroutine-desc.rs:7:4
diff --git a/tests/ui/async-await/dont-suggest-missing-await.stderr b/tests/ui/async-await/dont-suggest-missing-await.stderr
index 45a226c31f8..2ca52b2d5f5 100644
--- a/tests/ui/async-await/dont-suggest-missing-await.stderr
+++ b/tests/ui/async-await/dont-suggest-missing-await.stderr
@@ -6,20 +6,11 @@ LL |         take_u32(x)
    |         |
    |         arguments to this function are incorrect
    |
-note: calling an async function returns a future
-  --> $DIR/dont-suggest-missing-await.rs:14:18
-   |
-LL |         take_u32(x)
-   |                  ^
 note: function defined here
   --> $DIR/dont-suggest-missing-await.rs:5:4
    |
 LL | fn take_u32(x: u32) {}
    |    ^^^^^^^^ ------
-help: consider `await`ing on the `Future`
-   |
-LL |         take_u32(x.await)
-   |                   ++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/async-await/in-trait/dyn-compatibility.rs b/tests/ui/async-await/in-trait/dyn-compatibility.rs
index 8174a803e79..c1b1ec79784 100644
--- a/tests/ui/async-await/in-trait/dyn-compatibility.rs
+++ b/tests/ui/async-await/in-trait/dyn-compatibility.rs
@@ -7,5 +7,5 @@ trait Foo {
 
 fn main() {
     let x: &dyn Foo = todo!();
-    //~^ ERROR the trait `Foo` cannot be made into an object
+    //~^ ERROR the trait `Foo` is not dyn compatible
 }
diff --git a/tests/ui/async-await/in-trait/dyn-compatibility.stderr b/tests/ui/async-await/in-trait/dyn-compatibility.stderr
index 5cc3b6800dd..c6c406902f6 100644
--- a/tests/ui/async-await/in-trait/dyn-compatibility.stderr
+++ b/tests/ui/async-await/in-trait/dyn-compatibility.stderr
@@ -1,14 +1,15 @@
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/dyn-compatibility.rs:9:12
    |
 LL |     let x: &dyn Foo = todo!();
-   |            ^^^^^^^^ `Foo` cannot be made into an object
+   |            ^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/dyn-compatibility.rs:5:14
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     async fn foo(&self);
    |              ^^^ ...because method `foo` is `async`
    = help: consider moving `foo` to another trait
diff --git a/tests/ui/async-await/inference_var_self_argument.rs b/tests/ui/async-await/inference_var_self_argument.rs
index 4d5ac4abb19..d03f2b5c50b 100644
--- a/tests/ui/async-await/inference_var_self_argument.rs
+++ b/tests/ui/async-await/inference_var_self_argument.rs
@@ -3,7 +3,7 @@
 
 trait Foo {
     async fn foo(self: &dyn Foo) {
-        //~^ ERROR: `Foo` cannot be made into an object
+        //~^ ERROR: `Foo` is not dyn compatible
         //~| ERROR invalid `self` parameter type: `&dyn Foo`
         todo!()
     }
diff --git a/tests/ui/async-await/inference_var_self_argument.stderr b/tests/ui/async-await/inference_var_self_argument.stderr
index 7b7b3dbc757..a674fc0f3a5 100644
--- a/tests/ui/async-await/inference_var_self_argument.stderr
+++ b/tests/ui/async-await/inference_var_self_argument.stderr
@@ -7,17 +7,18 @@ LL |     async fn foo(self: &dyn Foo) {
    = note: type of `self` must be `Self` or a type that dereferences to it
    = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/inference_var_self_argument.rs:5:5
    |
 LL |     async fn foo(self: &dyn Foo) {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/inference_var_self_argument.rs:5:14
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     async fn foo(self: &dyn Foo) {
    |              ^^^ ...because method `foo` is `async`
    = help: consider moving `foo` to another trait
diff --git a/tests/ui/async-await/issue-68523-start.rs b/tests/ui/async-await/issue-68523-start.rs
deleted file mode 100644
index ee3baf4990c..00000000000
--- a/tests/ui/async-await/issue-68523-start.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ edition:2018
-
-#![feature(start)]
-
-#[start]
-pub async fn start(_: isize, _: *const *const u8) -> isize {
-//~^ ERROR `#[start]` function is not allowed to be `async`
-    0
-}
diff --git a/tests/ui/async-await/issue-68523-start.stderr b/tests/ui/async-await/issue-68523-start.stderr
deleted file mode 100644
index 5b76ab56e24..00000000000
--- a/tests/ui/async-await/issue-68523-start.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0752]: `#[start]` function is not allowed to be `async`
-  --> $DIR/issue-68523-start.rs:6:1
-   |
-LL | pub async fn start(_: isize, _: *const *const u8) -> isize {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `#[start]` is not allowed to be `async`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0752`.
diff --git a/tests/ui/attr-start.rs b/tests/ui/attr-start.rs
deleted file mode 100644
index 232f50955b2..00000000000
--- a/tests/ui/attr-start.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ run-pass
-
-#![feature(start)]
-
-#[start]
-fn start(_argc: isize, _argv: *const *const u8) -> isize {
-    return 0;
-}
diff --git a/tests/ui/borrowck/array-disjoint-borrows-issue-135671.rs b/tests/ui/borrowck/array-disjoint-borrows-issue-135671.rs
new file mode 100644
index 00000000000..74b5cfcfb04
--- /dev/null
+++ b/tests/ui/borrowck/array-disjoint-borrows-issue-135671.rs
@@ -0,0 +1,30 @@
+// This is a regression test for issue #135671 where a MIR refactor about arrays and their lengths
+// unexpectedly caused borrowck errors for disjoint borrows of array elements, for which we had no
+// tests. This is a collection of a few code samples from that issue.
+
+//@ check-pass
+
+struct Test {
+    a: i32,
+    b: i32,
+}
+
+fn one() {
+    let inputs: &mut [_] = &mut [Test { a: 0, b: 0 }];
+    let a = &mut inputs[0].a;
+    let b = &mut inputs[0].b;
+
+    *a = 0;
+    *b = 1;
+}
+
+fn two() {
+    let slice = &mut [(0, 0)][..];
+    std::mem::swap(&mut slice[0].0, &mut slice[0].1);
+}
+
+fn three(a: &mut [(i32, i32)], i: usize, j: usize) -> (&mut i32, &mut i32) {
+    (&mut a[i].0, &mut a[j].1)
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/borrowck-describe-lvalue.rs b/tests/ui/borrowck/borrowck-describe-lvalue.rs
index f3a4b382fa8..cdcff69d6e5 100644
--- a/tests/ui/borrowck/borrowck-describe-lvalue.rs
+++ b/tests/ui/borrowck/borrowck-describe-lvalue.rs
@@ -231,6 +231,7 @@ fn main() {
         let x = &mut v;
         v[0].y;
         //~^ ERROR cannot use `v[_].y` because it was mutably borrowed
+        //~| ERROR cannot use `*v` because it was mutably borrowed
         drop(x);
     }
     // Field of constant index
diff --git a/tests/ui/borrowck/borrowck-describe-lvalue.stderr b/tests/ui/borrowck/borrowck-describe-lvalue.stderr
index 666a21808d8..11f2e42d42b 100644
--- a/tests/ui/borrowck/borrowck-describe-lvalue.stderr
+++ b/tests/ui/borrowck/borrowck-describe-lvalue.stderr
@@ -1,5 +1,5 @@
 error[E0499]: cannot borrow `x` as mutable more than once at a time
-  --> $DIR/borrowck-describe-lvalue.rs:253:13
+  --> $DIR/borrowck-describe-lvalue.rs:254:13
    |
 LL |             let y = &mut x;
    |                     ------ first mutable borrow occurs here
@@ -9,7 +9,7 @@ LL |             *y = 1;
    |             ------ first borrow later used here
 
 error[E0499]: cannot borrow `x` as mutable more than once at a time
-  --> $DIR/borrowck-describe-lvalue.rs:263:20
+  --> $DIR/borrowck-describe-lvalue.rs:264:20
    |
 LL |                    let y = &mut x;
    |                            ------ first mutable borrow occurs here
@@ -19,7 +19,7 @@ LL |                    *y = 1;
    |                    ------ first borrow later used here
 
 error: captured variable cannot escape `FnMut` closure body
-  --> $DIR/borrowck-describe-lvalue.rs:261:16
+  --> $DIR/borrowck-describe-lvalue.rs:262:16
    |
 LL |           let mut x = 0;
    |               ----- variable defined here
@@ -300,6 +300,17 @@ LL |             S  { x: F { y: ref x0, .. }, .. } =>
 LL |         drop(x);
    |              - mutable borrow later used here
 
+error[E0503]: cannot use `*v` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:232:9
+   |
+LL |         let x = &mut v;
+   |                 ------ `v` is borrowed here
+LL |         v[0].y;
+   |         ^^^^ use of borrowed `v`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
 error[E0503]: cannot use `v[_].y` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:232:9
    |
@@ -307,12 +318,12 @@ LL |         let x = &mut v;
    |                 ------ `v` is borrowed here
 LL |         v[0].y;
    |         ^^^^^^ use of borrowed `v`
-LL |
+...
 LL |         drop(x);
    |              - borrow later used here
 
 error[E0502]: cannot borrow `v[..].x` as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-describe-lvalue.rs:242:24
+  --> $DIR/borrowck-describe-lvalue.rs:243:24
    |
 LL |         let x = &mut v;
    |                 ------ mutable borrow occurs here
@@ -346,7 +357,7 @@ LL |             drop(x);
    |                  - mutable borrow later used here
 
 error[E0382]: use of moved value: `x`
-  --> $DIR/borrowck-describe-lvalue.rs:273:22
+  --> $DIR/borrowck-describe-lvalue.rs:274:22
    |
 LL |                 drop(x);
    |                      - value moved here
@@ -355,7 +366,7 @@ LL |                 drop(x);
    |
    = note: move occurs because `x` has type `Vec<i32>`, which does not implement the `Copy` trait
 
-error: aborting due to 31 previous errors
+error: aborting due to 32 previous errors
 
 Some errors have detailed explanations: E0382, E0499, E0502, E0503.
 For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.rs b/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.rs
index 2d22c9a856f..3abc81e191e 100644
--- a/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.rs
+++ b/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.rs
@@ -12,7 +12,8 @@ fn arrays_1() {
     // c will capture `arr` completely, therefore another index into the
     // array can't be modified here
     arr[1] += 10;
-    //~^ ERROR: cannot use `arr[_]` because it was mutably borrowed
+    //~^ ERROR: cannot use `arr` because it was mutably borrowed
+    //~| ERROR: cannot use `arr[_]` because it was mutably borrowed
     c();
 }
 
@@ -54,7 +55,8 @@ fn arrays_4() {
     // c will capture `arr` completely, therefore we cannot borrow another index
     // into the array.
     println!("{}", arr[3]);
-    //~^ ERROR: cannot borrow `arr[_]` as immutable because it is also borrowed as mutable
+    //~^ ERROR: cannot use `arr` because it was mutably borrowed
+    //~| ERROR: cannot borrow `arr[_]` as immutable because it is also borrowed as mutable
 
     c();
 }
diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr b/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr
index 97ecdfab820..9e5200ef34b 100644
--- a/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr
+++ b/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr
@@ -1,3 +1,17 @@
+error[E0503]: cannot use `arr` because it was mutably borrowed
+  --> $DIR/arrays.rs:14:5
+   |
+LL |     let mut c = || {
+   |                 -- `arr` is borrowed here
+LL |         arr[0] += 10;
+   |         --- borrow occurs due to use of `arr` in closure
+...
+LL |     arr[1] += 10;
+   |     ^^^^^^ use of borrowed `arr`
+...
+LL |     c();
+   |     - borrow later used here
+
 error[E0503]: cannot use `arr[_]` because it was mutably borrowed
   --> $DIR/arrays.rs:14:5
    |
@@ -8,12 +22,12 @@ LL |         arr[0] += 10;
 ...
 LL |     arr[1] += 10;
    |     ^^^^^^^^^^^^ use of borrowed `arr`
-LL |
+...
 LL |     c();
    |     - borrow later used here
 
 error[E0506]: cannot assign to `arr[_]` because it is borrowed
-  --> $DIR/arrays.rs:28:5
+  --> $DIR/arrays.rs:29:5
    |
 LL |     let c = || {
    |             -- `arr[_]` is borrowed here
@@ -27,7 +41,7 @@ LL |     c();
    |     - borrow later used here
 
 error[E0506]: cannot assign to `arr[_]` because it is borrowed
-  --> $DIR/arrays.rs:42:5
+  --> $DIR/arrays.rs:43:5
    |
 LL |     let c = || {
    |             -- `arr[_]` is borrowed here
@@ -40,8 +54,22 @@ LL |
 LL |     c();
    |     - borrow later used here
 
+error[E0503]: cannot use `arr` because it was mutably borrowed
+  --> $DIR/arrays.rs:57:20
+   |
+LL |     let mut c = || {
+   |                 -- `arr` is borrowed here
+LL |         arr[1] += 10;
+   |         --- borrow occurs due to use of `arr` in closure
+...
+LL |     println!("{}", arr[3]);
+   |                    ^^^^^^ use of borrowed `arr`
+...
+LL |     c();
+   |     - borrow later used here
+
 error[E0502]: cannot borrow `arr[_]` as immutable because it is also borrowed as mutable
-  --> $DIR/arrays.rs:56:20
+  --> $DIR/arrays.rs:57:20
    |
 LL |     let mut c = || {
    |                 -- mutable borrow occurs here
@@ -57,7 +85,7 @@ LL |     c();
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0502]: cannot borrow `arr` as immutable because it is also borrowed as mutable
-  --> $DIR/arrays.rs:71:24
+  --> $DIR/arrays.rs:73:24
    |
 LL |     let mut c = || {
    |                 -- mutable borrow occurs here
@@ -70,7 +98,7 @@ LL |     println!("{:#?}", &arr[3..2]);
 LL |     c();
    |     - mutable borrow later used here
 
-error: aborting due to 5 previous errors
+error: aborting due to 7 previous errors
 
 Some errors have detailed explanations: E0502, E0503, E0506.
 For more information about an error, try `rustc --explain E0502`.
diff --git a/tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.stderr b/tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.stderr
index 542be2dbc30..20257bbaf28 100644
--- a/tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.stderr
+++ b/tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.stderr
@@ -1,16 +1,17 @@
-error[E0038]: the trait `DynIncompatible` cannot be made into an object
+error[E0038]: the trait `DynIncompatible` is not dyn compatible
   --> $DIR/coherence-impl-trait-for-trait-dyn-compatible.rs:7:26
    |
 LL | impl DynIncompatible for dyn DynIncompatible { }
-   |                          ^^^^^^^^^^^^^^^^^^^ `DynIncompatible` cannot be made into an object
+   |                          ^^^^^^^^^^^^^^^^^^^ `DynIncompatible` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/coherence-impl-trait-for-trait-dyn-compatible.rs:6:45
    |
 LL | trait DynIncompatible { fn eq(&self, other: Self); }
    |       ---------------                       ^^^^ ...because method `eq` references the `Self` type in this parameter
    |       |
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
    = help: consider moving `eq` to another trait
 
 error[E0046]: not all trait items implemented, missing: `eq`
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr
index 84281eb53c9..cd7f3a3c21d 100644
--- a/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr
@@ -1,28 +1,30 @@
-error[E0038]: the trait `ConstParamTy_` cannot be made into an object
-  --> $DIR/const_param_ty_dyn_compatibility.rs:6:12
+error[E0038]: the trait `ConstParamTy_` is not dyn compatible
+  --> $DIR/const_param_ty_dyn_compatibility.rs:6:16
    |
 LL | fn foo(a: &dyn ConstParamTy_) {}
-   |            ^^^^^^^^^^^^^^^^^ `ConstParamTy_` cannot be made into an object
+   |                ^^^^^^^^^^^^^ `ConstParamTy_` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $SRC_DIR/core/src/cmp.rs:LL:COL
    |
-   = note: the trait cannot be made into an object because it uses `Self` as a type parameter
+   = note: the trait is not dyn compatible because it uses `Self` as a type parameter
 help: consider using an opaque type instead
    |
 LL | fn foo(a: &impl ConstParamTy_) {}
    |            ~~~~
 
-error[E0038]: the trait `UnsizedConstParamTy` cannot be made into an object
-  --> $DIR/const_param_ty_dyn_compatibility.rs:9:12
+error[E0038]: the trait `UnsizedConstParamTy` is not dyn compatible
+  --> $DIR/const_param_ty_dyn_compatibility.rs:9:16
    |
 LL | fn bar(a: &dyn UnsizedConstParamTy) {}
-   |            ^^^^^^^^^^^^^^^^^^^^^^^ `UnsizedConstParamTy` cannot be made into an object
+   |                ^^^^^^^^^^^^^^^^^^^ `UnsizedConstParamTy` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $SRC_DIR/core/src/cmp.rs:LL:COL
    |
-   = note: the trait cannot be made into an object because it uses `Self` as a type parameter
+   = note: the trait is not dyn compatible because it uses `Self` as a type parameter
 help: consider using an opaque type instead
    |
 LL | fn bar(a: &impl UnsizedConstParamTy) {}
diff --git a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.rs b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.rs
index 1620e257667..9ab715d01f7 100644
--- a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.rs
+++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.rs
@@ -14,8 +14,8 @@ impl Foo for () {
     }
 }
 
-fn use_dyn(v: &dyn Foo) { //~ERROR the trait `Foo` cannot be made into an object
-    v.test(); //~ERROR the trait `Foo` cannot be made into an object
+fn use_dyn(v: &dyn Foo) { //~ERROR the trait `Foo` is not dyn compatible
+    v.test(); //~ERROR the trait `Foo` is not dyn compatible
 }
 
 fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr
index d2017615e67..763bc626c9d 100644
--- a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr
@@ -1,38 +1,40 @@
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/dyn-compatibility-err-ret.rs:17:16
    |
 LL | fn use_dyn(v: &dyn Foo) {
-   |                ^^^^^^^ `Foo` cannot be made into an object
+   |                ^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/dyn-compatibility-err-ret.rs:8:8
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn test(&self) -> [u8; bar::<Self>()];
    |        ^^^^           ^^^^^^^^^^^^^^^^^^^ ...because method `test` references the `Self` type in its return type
    |        |
    |        ...because method `test` references the `Self` type in its `where` clause
    = help: consider moving `test` to another trait
-   = help: only type `()` implements the trait, consider using it directly instead
+   = help: only type `()` implements `Foo`; consider using it directly instead.
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/dyn-compatibility-err-ret.rs:18:5
    |
 LL |     v.test();
-   |     ^^^^^^^^ `Foo` cannot be made into an object
+   |     ^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/dyn-compatibility-err-ret.rs:8:8
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn test(&self) -> [u8; bar::<Self>()];
    |        ^^^^           ^^^^^^^^^^^^^^^^^^^ ...because method `test` references the `Self` type in its return type
    |        |
    |        ...because method `test` references the `Self` type in its `where` clause
    = help: consider moving `test` to another trait
-   = help: only type `()` implements the trait, consider using it directly instead
+   = help: only type `()` implements `Foo`; consider using it directly instead.
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.rs b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.rs
index b3bbb842638..a7b771cd4f8 100644
--- a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.rs
+++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.rs
@@ -13,9 +13,9 @@ impl Foo for () {
 }
 
 fn use_dyn(v: &dyn Foo) {
-    //~^ ERROR the trait `Foo` cannot be made into an object
+    //~^ ERROR the trait `Foo` is not dyn compatible
     v.test();
-    //~^ ERROR the trait `Foo` cannot be made into an object
+    //~^ ERROR the trait `Foo` is not dyn compatible
 }
 
 fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr
index 26ca2d4df5f..56678e4e9af 100644
--- a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr
@@ -1,34 +1,36 @@
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/dyn-compatibility-err-where-bounds.rs:15:16
    |
 LL | fn use_dyn(v: &dyn Foo) {
-   |                ^^^^^^^ `Foo` cannot be made into an object
+   |                ^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/dyn-compatibility-err-where-bounds.rs:8:8
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn test(&self) where [u8; bar::<Self>()]: Sized;
    |        ^^^^ ...because method `test` references the `Self` type in its `where` clause
    = help: consider moving `test` to another trait
-   = help: only type `()` implements the trait, consider using it directly instead
+   = help: only type `()` implements `Foo`; consider using it directly instead.
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/dyn-compatibility-err-where-bounds.rs:17:5
    |
 LL |     v.test();
-   |     ^^^^^^^^ `Foo` cannot be made into an object
+   |     ^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/dyn-compatibility-err-where-bounds.rs:8:8
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn test(&self) where [u8; bar::<Self>()]: Sized;
    |        ^^^^ ...because method `test` references the `Self` type in its `where` clause
    = help: consider moving `test` to another trait
-   = help: only type `()` implements the trait, consider using it directly instead
+   = help: only type `()` implements `Foo`; consider using it directly instead.
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-102768.rs b/tests/ui/const-generics/generic_const_exprs/issue-102768.rs
index f2ad7d7ce8b..882b27a418e 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-102768.rs
+++ b/tests/ui/const-generics/generic_const_exprs/issue-102768.rs
@@ -13,7 +13,7 @@ const _: () = {
     //~| ERROR associated type takes 0 generic arguments but 1 generic argument
     //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments
     //~| ERROR associated type takes 0 generic arguments but 1 generic argument
-    //~| ERROR `X` cannot be made into an object
+    //~| ERROR `X` is not dyn compatible
 };
 
 fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr b/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr
index 9a75f372879..bd1811bd2cc 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr
@@ -92,17 +92,18 @@ LL |     type Y<'a>;
    |          ^
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0038]: the trait `X` cannot be made into an object
+error[E0038]: the trait `X` is not dyn compatible
   --> $DIR/issue-102768.rs:9:24
    |
 LL |     fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {}
-   |                        ^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object
+   |                        ^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-102768.rs:5:10
    |
 LL | trait X {
-   |       - this trait cannot be made into an object...
+   |       - this trait is not dyn compatible...
 LL |     type Y<'a>;
    |          ^ ...because it contains the generic associated type `Y`
    = help: consider moving `Y` to another trait
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr b/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr
index c851a8380f2..d90380396c1 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr
@@ -6,6 +6,6 @@ Box<dyn Any>
 query stack during panic:
 #0 [eval_to_allocation_raw] const-evaluating + checking `<impl at $DIR/issue-80742.rs:26:1: 28:32>::{constant#0}`
 #1 [eval_to_valtree] evaluating type-level constant
-end of query stack
+... and 2 other queries... use `env RUST_BACKTRACE=1` to see the full query stack
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/issues/index_array_bad_type.rs b/tests/ui/const-generics/issues/index_array_bad_type.rs
deleted file mode 100644
index 41e4dba026c..00000000000
--- a/tests/ui/const-generics/issues/index_array_bad_type.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-//@ check-fail
-//@ compile-flags: -C opt-level=0
-
-#![crate_type = "lib"]
-
-// This used to fail in the known-panics lint, as the MIR was ill-typed due to
-// the length constant not actually having type usize.
-// https://github.com/rust-lang/rust/issues/134352
-
-pub struct BadStruct<const N: i64>(pub [u8; N]);
-//~^ ERROR: the constant `N` is not of type `usize`
-
-pub fn bad_array_length_type(value: BadStruct<3>) -> u8 {
-    value.0[0]
-}
diff --git a/tests/ui/const-generics/issues/index_array_bad_type.stderr b/tests/ui/const-generics/issues/index_array_bad_type.stderr
deleted file mode 100644
index e4417192150..00000000000
--- a/tests/ui/const-generics/issues/index_array_bad_type.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: the constant `N` is not of type `usize`
-  --> $DIR/index_array_bad_type.rs:10:40
-   |
-LL | pub struct BadStruct<const N: i64>(pub [u8; N]);
-   |                                        ^^^^^^^ expected `usize`, found `i64`
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr
index 601c8647eee..308b02386f5 100644
--- a/tests/ui/consts/const-unstable-intrinsic.stderr
+++ b/tests/ui/consts/const-unstable-intrinsic.stderr
@@ -24,7 +24,10 @@ error: `size_of_val` is not yet stable as a const intrinsic
 LL |         unstable_intrinsic::size_of_val(&x);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: add `#![feature(unstable)]` to the crate attributes to enable
+help: add `#![feature(unstable)]` to the crate attributes to enable
+   |
+LL + #![feature(unstable)]
+   |
 
 error: `min_align_of_val` is not yet stable as a const intrinsic
   --> $DIR/const-unstable-intrinsic.rs:20:9
@@ -32,7 +35,10 @@ error: `min_align_of_val` is not yet stable as a const intrinsic
 LL |         unstable_intrinsic::min_align_of_val(&x);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: add `#![feature(unstable)]` to the crate attributes to enable
+help: add `#![feature(unstable)]` to the crate attributes to enable
+   |
+LL + #![feature(unstable)]
+   |
 
 error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]`
   --> $DIR/const-unstable-intrinsic.rs:24:9
diff --git a/tests/ui/consts/issue-65348.rs b/tests/ui/consts/issue-65348.rs
index 0d12da3926c..1443fcbe1c1 100644
--- a/tests/ui/consts/issue-65348.rs
+++ b/tests/ui/consts/issue-65348.rs
@@ -9,17 +9,15 @@ impl<T> Generic<T> {
 }
 
 pub const fn array<T>() -> &'static T {
-    #[expect(unconditional_panic)]
+    #[allow(unconditional_panic)]
     &Generic::<T>::ARRAY[0]
 }
 
 pub const fn newtype_array<T>() -> &'static T {
-    #[expect(unconditional_panic)]
     &Generic::<T>::NEWTYPE_ARRAY.0[0]
 }
 
 pub const fn array_field<T>() -> &'static T {
-    #[expect(unconditional_panic)]
     &(Generic::<T>::ARRAY_FIELD.0).1[0]
 }
 
diff --git a/tests/ui/consts/too_generic_eval_ice.stderr b/tests/ui/consts/too_generic_eval_ice.stderr
index b48be16a24c..3cc4377514a 100644
--- a/tests/ui/consts/too_generic_eval_ice.stderr
+++ b/tests/ui/consts/too_generic_eval_ice.stderr
@@ -32,13 +32,13 @@ LL |         [5; Self::HOST_SIZE] == [6; 0]
    = help: the following other types implement trait `PartialEq<Rhs>`:
              `&[T]` implements `PartialEq<Vec<U, A>>`
              `&[T]` implements `PartialEq<[U; N]>`
+             `&[u8; N]` implements `PartialEq<ByteStr>`
+             `&[u8; N]` implements `PartialEq<ByteString>`
+             `&[u8]` implements `PartialEq<ByteStr>`
+             `&[u8]` implements `PartialEq<ByteString>`
              `&mut [T]` implements `PartialEq<Vec<U, A>>`
              `&mut [T]` implements `PartialEq<[U; N]>`
-             `[T; N]` implements `PartialEq<&[U]>`
-             `[T; N]` implements `PartialEq<&mut [U]>`
-             `[T; N]` implements `PartialEq<[U; N]>`
-             `[T; N]` implements `PartialEq<[U]>`
-           and 3 others
+           and 11 others
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_off.rs b/tests/ui/debuginfo/windows_gnu_split_debuginfo_off.rs
new file mode 100644
index 00000000000..3a8d9c998cf
--- /dev/null
+++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_off.rs
@@ -0,0 +1,29 @@
+//@ revisions: aarch64_gl i686_g i686_gl i686_uwp_g x86_64_g x86_64_gl x86_64_uwp_g
+//@ compile-flags: --crate-type cdylib -Csplit-debuginfo=off
+//@ check-pass
+
+//@[aarch64_gl] compile-flags: --target aarch64-pc-windows-gnullvm
+//@[aarch64_gl] needs-llvm-components: aarch64
+
+//@[i686_g] compile-flags: --target i686-pc-windows-gnu
+//@[i686_g] needs-llvm-components: x86
+
+//@[i686_gl] compile-flags: --target i686-pc-windows-gnullvm
+//@[i686_gl] needs-llvm-components: x86
+
+//@[i686_uwp_g] compile-flags: --target i686-uwp-windows-gnu
+//@[i686_uwp_g] needs-llvm-components: x86
+
+//@[x86_64_g] compile-flags: --target x86_64-pc-windows-gnu
+//@[x86_64_g] needs-llvm-components: x86
+
+//@[x86_64_gl] compile-flags: --target x86_64-pc-windows-gnullvm
+//@[x86_64_gl] needs-llvm-components: x86
+
+//@[x86_64_uwp_g] compile-flags: --target x86_64-uwp-windows-gnu
+//@[x86_64_uwp_g] needs-llvm-components: x86
+
+#![feature(no_core)]
+
+#![no_core]
+#![no_std]
diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.aarch64_gl.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.aarch64_gl.stderr
new file mode 100644
index 00000000000..f3465e64976
--- /dev/null
+++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.aarch64_gl.stderr
@@ -0,0 +1,4 @@
+error: `-Csplit-debuginfo=packed` is unstable on this platform
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_g.stderr
new file mode 100644
index 00000000000..f3465e64976
--- /dev/null
+++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_g.stderr
@@ -0,0 +1,4 @@
+error: `-Csplit-debuginfo=packed` is unstable on this platform
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_gl.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_gl.stderr
new file mode 100644
index 00000000000..f3465e64976
--- /dev/null
+++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_gl.stderr
@@ -0,0 +1,4 @@
+error: `-Csplit-debuginfo=packed` is unstable on this platform
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_uwp_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_uwp_g.stderr
new file mode 100644
index 00000000000..f3465e64976
--- /dev/null
+++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_uwp_g.stderr
@@ -0,0 +1,4 @@
+error: `-Csplit-debuginfo=packed` is unstable on this platform
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.rs b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.rs
new file mode 100644
index 00000000000..896bbac7d8e
--- /dev/null
+++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.rs
@@ -0,0 +1,29 @@
+//@ revisions: aarch64_gl i686_g i686_gl i686_uwp_g x86_64_g x86_64_gl x86_64_uwp_g
+//@ compile-flags: --crate-type cdylib -Csplit-debuginfo=packed
+//@ error-pattern: error: `-Csplit-debuginfo=packed` is unstable on this platform
+
+//@[aarch64_gl] compile-flags: --target aarch64-pc-windows-gnullvm
+//@[aarch64_gl] needs-llvm-components: aarch64
+
+//@[i686_g] compile-flags: --target i686-pc-windows-gnu
+//@[i686_g] needs-llvm-components: x86
+
+//@[i686_gl] compile-flags: --target i686-pc-windows-gnullvm
+//@[i686_gl] needs-llvm-components: x86
+
+//@[i686_uwp_g] compile-flags: --target i686-uwp-windows-gnu
+//@[i686_uwp_g] needs-llvm-components: x86
+
+//@[x86_64_g] compile-flags: --target x86_64-pc-windows-gnu
+//@[x86_64_g] needs-llvm-components: x86
+
+//@[x86_64_gl] compile-flags: --target x86_64-pc-windows-gnullvm
+//@[x86_64_gl] needs-llvm-components: x86
+
+//@[x86_64_uwp_g] compile-flags: --target x86_64-uwp-windows-gnu
+//@[x86_64_uwp_g] needs-llvm-components: x86
+
+#![feature(no_core)]
+
+#![no_core]
+#![no_std]
diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_g.stderr
new file mode 100644
index 00000000000..f3465e64976
--- /dev/null
+++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_g.stderr
@@ -0,0 +1,4 @@
+error: `-Csplit-debuginfo=packed` is unstable on this platform
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_gl.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_gl.stderr
new file mode 100644
index 00000000000..f3465e64976
--- /dev/null
+++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_gl.stderr
@@ -0,0 +1,4 @@
+error: `-Csplit-debuginfo=packed` is unstable on this platform
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_uwp_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_uwp_g.stderr
new file mode 100644
index 00000000000..f3465e64976
--- /dev/null
+++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_uwp_g.stderr
@@ -0,0 +1,4 @@
+error: `-Csplit-debuginfo=packed` is unstable on this platform
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.aarch64_gl.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.aarch64_gl.stderr
new file mode 100644
index 00000000000..0964e21b13b
--- /dev/null
+++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.aarch64_gl.stderr
@@ -0,0 +1,4 @@
+error: `-Csplit-debuginfo=unpacked` is unstable on this platform
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_g.stderr
new file mode 100644
index 00000000000..0964e21b13b
--- /dev/null
+++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_g.stderr
@@ -0,0 +1,4 @@
+error: `-Csplit-debuginfo=unpacked` is unstable on this platform
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_gl.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_gl.stderr
new file mode 100644
index 00000000000..0964e21b13b
--- /dev/null
+++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_gl.stderr
@@ -0,0 +1,4 @@
+error: `-Csplit-debuginfo=unpacked` is unstable on this platform
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_uwp_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_uwp_g.stderr
new file mode 100644
index 00000000000..0964e21b13b
--- /dev/null
+++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_uwp_g.stderr
@@ -0,0 +1,4 @@
+error: `-Csplit-debuginfo=unpacked` is unstable on this platform
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.rs b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.rs
new file mode 100644
index 00000000000..54a88c91217
--- /dev/null
+++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.rs
@@ -0,0 +1,29 @@
+//@ revisions: aarch64_gl i686_g i686_gl i686_uwp_g x86_64_g x86_64_gl x86_64_uwp_g
+//@ compile-flags: --crate-type cdylib -Csplit-debuginfo=unpacked
+//@ error-pattern: error: `-Csplit-debuginfo=unpacked` is unstable on this platform
+
+//@[aarch64_gl] compile-flags: --target aarch64-pc-windows-gnullvm
+//@[aarch64_gl] needs-llvm-components: aarch64
+
+//@[i686_g] compile-flags: --target i686-pc-windows-gnu
+//@[i686_g] needs-llvm-components: x86
+
+//@[i686_gl] compile-flags: --target i686-pc-windows-gnullvm
+//@[i686_gl] needs-llvm-components: x86
+
+//@[i686_uwp_g] compile-flags: --target i686-uwp-windows-gnu
+//@[i686_uwp_g] needs-llvm-components: x86
+
+//@[x86_64_g] compile-flags: --target x86_64-pc-windows-gnu
+//@[x86_64_g] needs-llvm-components: x86
+
+//@[x86_64_gl] compile-flags: --target x86_64-pc-windows-gnullvm
+//@[x86_64_gl] needs-llvm-components: x86
+
+//@[x86_64_uwp_g] compile-flags: --target x86_64-uwp-windows-gnu
+//@[x86_64_uwp_g] needs-llvm-components: x86
+
+#![feature(no_core)]
+
+#![no_core]
+#![no_std]
diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_g.stderr
new file mode 100644
index 00000000000..0964e21b13b
--- /dev/null
+++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_g.stderr
@@ -0,0 +1,4 @@
+error: `-Csplit-debuginfo=unpacked` is unstable on this platform
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_gl.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_gl.stderr
new file mode 100644
index 00000000000..0964e21b13b
--- /dev/null
+++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_gl.stderr
@@ -0,0 +1,4 @@
+error: `-Csplit-debuginfo=unpacked` is unstable on this platform
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_uwp_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_uwp_g.stderr
new file mode 100644
index 00000000000..0964e21b13b
--- /dev/null
+++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_uwp_g.stderr
@@ -0,0 +1,4 @@
+error: `-Csplit-debuginfo=unpacked` is unstable on this platform
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/deprecation/deprecation-lint.stderr b/tests/ui/deprecation/deprecation-lint.stderr
index 2098073409d..95ae1b04d86 100644
--- a/tests/ui/deprecation/deprecation-lint.stderr
+++ b/tests/ui/deprecation/deprecation-lint.stderr
@@ -739,8 +739,11 @@ LL |              _)
 error[E0451]: field `i` of struct `this_crate::nested::DeprecatedStruct` is private
   --> $DIR/deprecation-lint.rs:280:13
    |
+LL |         let _ = nested::DeprecatedStruct {
+   |                 ------------------------ in this type
+LL |
 LL |             i: 0
-   |             ^^^^ private field
+   |             ^ private field
 
 error: aborting due to 123 previous errors
 
diff --git a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.rs b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.rs
index c9a097d3610..9cd32ffeb6d 100644
--- a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.rs
+++ b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.rs
@@ -2,6 +2,6 @@
 
 fn main() {
     let _: &Copy + 'static; //~ ERROR expected a path
-    //~^ ERROR cannot be made into an object
+    //~^ ERROR is not dyn compatible
     let _: &'static Copy + 'static; //~ ERROR expected a path
 }
diff --git a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr
index 8ef0d178444..7994ddf11c3 100644
--- a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr
+++ b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr
@@ -20,14 +20,15 @@ help: try adding parentheses
 LL |     let _: &'static (Copy + 'static);
    |                     +              +
 
-error[E0038]: the trait `Copy` cannot be made into an object
+error[E0038]: the trait `Copy` is not dyn compatible
   --> $DIR/trait-object-reference-without-parens-suggestion.rs:4:12
    |
 LL |     let _: &Copy + 'static;
-   |            ^^^^^ `Copy` cannot be made into an object
+   |            ^^^^^ `Copy` is not dyn compatible
    |
-   = note: the trait cannot be made into an object because it requires `Self: Sized`
-   = note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+   = note: the trait is not dyn compatible because it requires `Self: Sized`
+   = note: for a trait to be dyn compatible it needs to allow building a vtable
+           for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/drop/drop-order-comparisons.e2021.fixed b/tests/ui/drop/drop-order-comparisons.e2021.fixed
new file mode 100644
index 00000000000..78cf421cfbf
--- /dev/null
+++ b/tests/ui/drop/drop-order-comparisons.e2021.fixed
@@ -0,0 +1,575 @@
+// This tests various aspects of the drop order with a focus on:
+//
+// - The lifetime of temporaries with the `if let` construct (and with
+// various similar constructs) and how these lifetimes were shortened
+// for `if let` in Rust 2024.
+//
+// - The shortening of the lifetimes of temporaries in tail
+// expressions in Rust 2024.
+//
+// - The behavior of `let` chains and how this behavior compares to
+// nested `if let` expressions and chained `let .. else` statements.
+//
+// In the tests below, `Events` tracks a sequence of numbered events.
+// Calling `e.mark(..)` logs a numbered event immediately.  Calling
+// `e.ok(..)` or `e.err(..)` returns an `Ok(_)` or `Err(_)` value,
+// respectively, and logs the numbered event when that value is
+// dropped.  Calling `e.assert()` verifies that the correct number of
+// events were logged and that they were logged in the correct order.
+
+//@ revisions: e2021 e2024
+//@ [e2021] edition: 2021
+//@ [e2021] run-rustfix
+//@ [e2021] rustfix-only-machine-applicable
+//@ [e2024] edition: 2024
+//@ run-pass
+
+#![feature(let_chains)]
+#![cfg_attr(e2021, warn(rust_2024_compatibility))]
+
+fn t_bindings() {
+    let e = Events::new();
+    _ = {
+        e.mark(1);
+        let _v = e.ok(8);
+        let _v = e.ok(2).is_ok();
+        let _ = e.ok(3);
+        let Ok(_) = e.ok(4) else { unreachable!() };
+        let Ok(_) = e.ok(5).as_ref() else { unreachable!() };
+        let _v = e.ok(7);
+        e.mark(6);
+    };
+    e.assert(8);
+}
+
+fn t_tuples() {
+    let e = Events::new();
+    _ = (e.ok(1), e.ok(4).is_ok(), e.ok(2), e.ok(3).is_ok());
+    e.assert(4);
+}
+
+fn t_arrays() {
+    let e = Events::new();
+    trait Tr {}
+    impl<T> Tr for T {}
+    fn b<'a, T: 'a>(x: T) -> Box<dyn Tr + 'a> {
+        Box::new(x)
+    }
+    _ = [b(e.ok(1)), b(e.ok(4).is_ok()), b(e.ok(2)), b(e.ok(3).is_ok())];
+    e.assert(4);
+}
+
+fn t_fncalls() {
+    let e = Events::new();
+    let f = |_, _, _, _| {};
+    _ = f(e.ok(2), e.ok(4).is_ok(), e.ok(1), e.ok(3).is_ok());
+    e.assert(4);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_tailexpr_bindings() {
+    let e = Events::new();
+    _ = ({
+        let _v = e.ok(2);
+        let _v = e.ok(1);
+        e.ok(5).is_ok()
+        //[e2021]~^ WARN relative drop order changing in Rust 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+    }, e.mark(3), e.ok(4));
+    e.assert(5);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_tailexpr_bindings() {
+    let e = Events::new();
+    _ = ({
+        let _v = e.ok(3);
+        let _v = e.ok(2);
+        e.ok(1).is_ok()
+    }, e.mark(4), e.ok(5));
+    e.assert(5);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_tailexpr_tuples() {
+    let e = Events::new();
+    _ = ({
+        (e.ok(2), e.ok(6).is_ok(), e.ok(3), e.ok(5).is_ok())
+        //[e2021]~^ WARN relative drop order changing in Rust 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        //[e2021]~| WARN relative drop order changing in Rust 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+    }, e.mark(1), e.ok(4));
+    e.assert(6);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_tailexpr_tuples() {
+    let e = Events::new();
+    _ = ({
+        (e.ok(4), e.ok(2).is_ok(), e.ok(5), e.ok(1).is_ok())
+    }, e.mark(3), e.ok(6));
+    e.assert(6);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_then() {
+    let e = Events::new();
+    _ = (match e.ok(4).as_ref() { Ok(_) => {
+            //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(1);
+    } _ => {}}, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_then() {
+    let e = Events::new();
+    _ = (if let Ok(_) = e.ok(2).as_ref() {
+            e.mark(1);
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_else() {
+    let e = Events::new();
+    _ = (match e.err(4).as_ref() { Ok(_) => {} _ => {
+            //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(1);
+    }}, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_else() {
+    let e = Events::new();
+    _ = (if let Ok(_) = e.err(1).as_ref() {} else {
+            e.mark(2);
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[rustfmt::skip]
+fn t_match_then() {
+    let e = Events::new();
+    _ = (match e.ok(4).as_ref() {
+            Ok(_) => e.mark(1),
+            _ => unreachable!(),
+    }, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[rustfmt::skip]
+fn t_match_else() {
+    let e = Events::new();
+    _ = (match e.err(4).as_ref() {
+            Ok(_) => unreachable!(),
+            _ => e.mark(1),
+    }, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[rustfmt::skip]
+fn t_let_else_then() {
+    let e = Events::new();
+    _ = ('top: {
+         'chain: {
+            let Ok(_) = e.ok(1).as_ref() else { break 'chain };
+            // The "then" branch:
+            e.mark(2);
+            break 'top;
+        }
+        // The "else" branch:
+        unreachable!()
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[rustfmt::skip]
+fn t_let_else_else() {
+    let e = Events::new();
+    _ = ('top: {
+         'chain: {
+            let Ok(_) = e.err(1).as_ref() else { break 'chain };
+            // The "then" branch:
+            unreachable!();
+            #[allow(unreachable_code)]
+            break 'top;
+        }
+        // The "else" branch:
+        e.mark(2);
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_then_tailexpr() {
+    let e = Events::new();
+    _ = ({
+        if let Ok(_) = e.ok(4).as_ref() {
+            //[e2021]~^ WARN relative drop order changing in Rust 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(1);
+        }
+    }, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_then_tailexpr() {
+    let e = Events::new();
+    _ = ({
+        if let Ok(_) = e.ok(2).as_ref() {
+            e.mark(1);
+        }
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_else_tailexpr() {
+    let e = Events::new();
+    _ = ({
+        match e.err(4).as_ref() { Ok(_) => {} _ => {
+            //[e2021]~^ WARN relative drop order changing in Rust 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            //[e2021]~| WARN if let` assigns a shorter lifetime since Edition 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(1);
+        }}
+    }, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_else_tailexpr() {
+    let e = Events::new();
+    _ = ({
+        if let Ok(_) = e.err(1).as_ref() {} else {
+            e.mark(2);
+        }
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[rustfmt::skip]
+fn t_if_let_nested_then() {
+    let e = Events::new();
+    _ = {
+        // The unusual formatting, here and below, is to make the
+        // comparison with `let` chains more direct.
+        if e.ok(1).is_ok() {
+        if let true = e.ok(9).is_ok() {
+        if let Ok(_v) = e.ok(8) {
+        if let Ok(_) = e.ok(7) {
+        if let Ok(_) = e.ok(6).as_ref() {
+        if e.ok(2).is_ok() {
+        if let Ok(_v) = e.ok(5) {
+        if let Ok(_) = e.ok(4).as_ref() {
+            e.mark(3);
+        }}}}}}}}
+    };
+    e.assert(9);
+}
+
+#[rustfmt::skip]
+fn t_let_else_chained_then() {
+    let e = Events::new();
+    _ = 'top: {
+        'chain: {
+            if e.ok(1).is_ok() {} else { break 'chain };
+            let true = e.ok(2).is_ok() else { break 'chain };
+            let Ok(_v) = e.ok(9) else { break 'chain };
+            let Ok(_) = e.ok(3) else { break 'chain };
+            let Ok(_) = e.ok(4).as_ref() else { break 'chain };
+            if e.ok(5).is_ok() {} else { break 'chain };
+            let Ok(_v) = e.ok(8) else { break 'chain };
+            let Ok(_) = e.ok(6).as_ref() else { break 'chain };
+            // The "then" branch:
+            e.mark(7);
+            break 'top;
+        }
+        // The "else" branch:
+        unreachable!()
+    };
+    e.assert(9);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_chains_then() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok()
+        && let true = e.ok(9).is_ok()
+        && let Ok(_v) = e.ok(5)
+        && let Ok(_) = e.ok(8)
+        && let Ok(_) = e.ok(7).as_ref()
+        && e.ok(2).is_ok()
+        && let Ok(_v) = e.ok(4)
+        && let Ok(_) = e.ok(6).as_ref() {
+            e.mark(3);
+        };
+    e.assert(9);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_chains_then() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok()
+        && let true = e.ok(9).is_ok()
+        && let Ok(_v) = e.ok(8)
+        && let Ok(_) = e.ok(7)
+        && let Ok(_) = e.ok(6).as_ref()
+        && e.ok(2).is_ok()
+        && let Ok(_v) = e.ok(5)
+        && let Ok(_) = e.ok(4).as_ref() {
+            e.mark(3);
+        };
+    e.assert(9);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_nested_else() {
+    let e = Events::new();
+    _ = if e.err(1).is_ok() {} else {
+        match e.err(9).is_ok() { true => {} _ => {
+        //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        match e.err(8) { Ok(_v) => {} _ => {
+        //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        match e.err(7) { Ok(_) => {} _ => {
+        //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        match e.err(6).as_ref() { Ok(_) => {} _ => {
+        //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        if e.err(2).is_ok() {} else {
+        match e.err(5) { Ok(_v) => {} _ => {
+        //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        match e.err(4) { Ok(_) => {} _ => {
+            //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(3);
+        }}}}}}}}}}}}}};
+    e.assert(9);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_nested_else() {
+    let e = Events::new();
+    _ = if e.err(1).is_ok() {} else {
+        if let true = e.err(2).is_ok() {} else {
+        if let Ok(_v) = e.err(3) {} else {
+        if let Ok(_) = e.err(4) {} else {
+        if let Ok(_) = e.err(5).as_ref() {} else {
+        if e.err(6).is_ok() {} else {
+        if let Ok(_v) = e.err(7) {} else {
+        if let Ok(_) = e.err(8) {} else {
+            e.mark(9);
+        }}}}}}}};
+    e.assert(9);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_nested_then_else() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok() {
+        if let true = e.ok(9).is_ok() {
+        if let Ok(_v) = e.ok(8) {
+        if let Ok(_) = e.ok(7) {
+        if let Ok(_) = e.ok(6).as_ref() {
+        if e.ok(2).is_ok() {
+        if let Ok(_v) = e.ok(5) {
+        match e.err(4).as_ref() { Ok(_) => {} _ => {
+            //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(3);
+        }}}}}}}}};
+    e.assert(9);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_nested_then_else() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok() {
+        if let true = e.ok(9).is_ok() {
+        if let Ok(_v) = e.ok(8) {
+        if let Ok(_) = e.ok(7) {
+        if let Ok(_) = e.ok(6).as_ref() {
+        if e.ok(2).is_ok() {
+        if let Ok(_v) = e.ok(5) {
+        if let Ok(_) = e.err(3).as_ref() {} else {
+            e.mark(4);
+        }}}}}}}};
+    e.assert(9);
+}
+
+#[rustfmt::skip]
+fn t_let_else_chained_then_else() {
+    let e = Events::new();
+    _ = 'top: {
+        'chain: {
+            if e.ok(1).is_ok() {} else { break 'chain };
+            let true = e.ok(2).is_ok() else { break 'chain };
+            let Ok(_v) = e.ok(8) else { break 'chain };
+            let Ok(_) = e.ok(3) else { break 'chain };
+            let Ok(_) = e.ok(4).as_ref() else { break 'chain };
+            if e.ok(5).is_ok() {} else { break 'chain };
+            let Ok(_v) = e.ok(7) else { break 'chain };
+            let Ok(_) = e.err(6).as_ref() else { break 'chain };
+            // The "then" branch:
+            unreachable!();
+            #[allow(unreachable_code)]
+            break 'top;
+        }
+        // The "else" branch:
+        e.mark(9);
+    };
+    e.assert(9);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_chains_then_else() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok()
+        && let true = e.ok(9).is_ok()
+        && let Ok(_v) = e.ok(4)
+        && let Ok(_) = e.ok(8)
+        && let Ok(_) = e.ok(7).as_ref()
+        && e.ok(2).is_ok()
+        && let Ok(_v) = e.ok(3)
+        && let Ok(_) = e.err(6) {} else {
+            e.mark(5);
+        };
+    e.assert(9);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_chains_then_else() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok()
+        && let true = e.ok(8).is_ok()
+        && let Ok(_v) = e.ok(7)
+        && let Ok(_) = e.ok(6)
+        && let Ok(_) = e.ok(5).as_ref()
+        && e.ok(2).is_ok()
+        && let Ok(_v) = e.ok(4)
+        && let Ok(_) = e.err(3) {} else {
+            e.mark(9);
+        };
+    e.assert(9);
+}
+
+fn main() {
+    t_bindings();
+    t_tuples();
+    t_arrays();
+    t_fncalls();
+    t_tailexpr_bindings();
+    t_tailexpr_tuples();
+    t_if_let_then();
+    t_if_let_else();
+    t_match_then();
+    t_match_else();
+    t_let_else_then();
+    t_let_else_else();
+    t_if_let_then_tailexpr();
+    t_if_let_else_tailexpr();
+    t_if_let_nested_then();
+    t_let_else_chained_then();
+    t_if_let_chains_then();
+    t_if_let_nested_else();
+    t_if_let_nested_then_else();
+    t_let_else_chained_then_else();
+    t_if_let_chains_then_else();
+}
+
+// # Test scaffolding
+
+use core::cell::RefCell;
+use std::collections::HashSet;
+
+/// A buffer to track the order of events.
+///
+/// First, numbered events are logged into this buffer.
+///
+/// Then, `assert` is called to verify that the correct number of
+/// events were logged, and that they were logged in the expected
+/// order.
+struct Events(RefCell<Option<Vec<u64>>>);
+
+impl Events {
+    const fn new() -> Self {
+        Self(RefCell::new(Some(Vec::new())))
+    }
+    #[track_caller]
+    fn assert(&self, max: u64) {
+        let buf = &self.0;
+        let v1 = buf.borrow().as_ref().unwrap().clone();
+        let mut v2 = buf.borrow().as_ref().unwrap().clone();
+        *buf.borrow_mut() = None;
+        v2.sort();
+        let uniq_len = v2.iter().collect::<HashSet<_>>().len();
+        // Check that the sequence is sorted.
+        assert_eq!(v1, v2);
+        // Check that there are no duplicates.
+        assert_eq!(v2.len(), uniq_len);
+        // Check that the length is the expected one.
+        assert_eq!(max, uniq_len as u64);
+        // Check that the last marker is the expected one.
+        assert_eq!(v2.last().unwrap(), &max);
+    }
+    /// Return an `Ok` value that logs its drop.
+    fn ok(&self, m: u64) -> Result<LogDrop<'_>, LogDrop<'_>> {
+        Ok(LogDrop(self, m))
+    }
+    /// Return an `Err` value that logs its drop.
+    fn err(&self, m: u64) -> Result<LogDrop, LogDrop> {
+        Err(LogDrop(self, m))
+    }
+    /// Log an event.
+    fn mark(&self, m: u64) {
+        self.0.borrow_mut().as_mut().unwrap().push(m);
+    }
+}
+
+impl Drop for Events {
+    fn drop(&mut self) {
+        if self.0.borrow().is_some() {
+            panic!("failed to call `Events::assert()`");
+        }
+    }
+}
+
+/// A type that logs its drop events.
+struct LogDrop<'b>(&'b Events, u64);
+
+impl<'b> Drop for LogDrop<'b> {
+    fn drop(&mut self) {
+        self.0.mark(self.1);
+    }
+}
diff --git a/tests/ui/drop/drop-order-comparisons.e2021.stderr b/tests/ui/drop/drop-order-comparisons.e2021.stderr
new file mode 100644
index 00000000000..158d18f6882
--- /dev/null
+++ b/tests/ui/drop/drop-order-comparisons.e2021.stderr
@@ -0,0 +1,477 @@
+warning: relative drop order changing in Rust 2024
+  --> $DIR/drop-order-comparisons.rs:76:9
+   |
+LL |       _ = ({
+   |  _________-
+LL | |         let _v = e.ok(2);
+   | |             --
+   | |             |
+   | |             `_v` calls a custom destructor
+   | |             `_v` will be dropped later as of Edition 2024
+LL | |         let _v = e.ok(1);
+   | |             --
+   | |             |
+   | |             this value will be stored in a temporary; let us call it `#2`
+   | |             `#2` will be dropped later as of Edition 2024
+LL | |         e.ok(5).is_ok()
+   | |         ^^^^^^^
+   | |         |
+   | |         this value will be stored in a temporary; let us call it `#3`
+   | |         up until Edition 2021 `#3` is dropped last but will be dropped earlier in Edition 2024
+...  |
+LL | |     }, e.mark(3), e.ok(4));
+   | |                          -
+   | |                          |
+   | |                          now the temporary value is dropped here, before the local variables in the block or statement
+   | |__________________________this value will be stored in a temporary; let us call it `#1`
+   |                            `#1` will be dropped later as of Edition 2024
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+note: `#3` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+note: `#1` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+note: `_v` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+note: `#2` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+note: the lint level is defined here
+  --> $DIR/drop-order-comparisons.rs:28:25
+   |
+LL | #![cfg_attr(e2021, warn(rust_2024_compatibility))]
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^
+   = note: `#[warn(tail_expr_drop_order)]` implied by `#[warn(rust_2024_compatibility)]`
+
+warning: relative drop order changing in Rust 2024
+  --> $DIR/drop-order-comparisons.rs:100:45
+   |
+LL |       _ = ({
+   |  _________-
+LL | |         (e.ok(2), e.ok(6).is_ok(), e.ok(3), e.ok(5).is_ok())
+   | |                                             ^^^^^^^
+   | |                                             |
+   | |                                             this value will be stored in a temporary; let us call it `#2`
+   | |                                             up until Edition 2021 `#2` is dropped last but will be dropped earlier in Edition 2024
+...  |
+LL | |     }, e.mark(1), e.ok(4));
+   | |                          -
+   | |                          |
+   | |                          now the temporary value is dropped here, before the local variables in the block or statement
+   | |__________________________this value will be stored in a temporary; let us call it `#1`
+   |                            `#1` will be dropped later as of Edition 2024
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+note: `#2` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+note: `#1` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+
+warning: relative drop order changing in Rust 2024
+  --> $DIR/drop-order-comparisons.rs:100:19
+   |
+LL |       _ = ({
+   |  _________-
+LL | |         (e.ok(2), e.ok(6).is_ok(), e.ok(3), e.ok(5).is_ok())
+   | |                   ^^^^^^^
+   | |                   |
+   | |                   this value will be stored in a temporary; let us call it `#2`
+   | |                   up until Edition 2021 `#2` is dropped last but will be dropped earlier in Edition 2024
+...  |
+LL | |     }, e.mark(1), e.ok(4));
+   | |                          -
+   | |                          |
+   | |                          now the temporary value is dropped here, before the local variables in the block or statement
+   | |__________________________this value will be stored in a temporary; let us call it `#1`
+   |                            `#1` will be dropped later as of Edition 2024
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+note: `#2` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+note: `#1` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+
+warning: relative drop order changing in Rust 2024
+  --> $DIR/drop-order-comparisons.rs:221:24
+   |
+LL |       _ = ({
+   |  _________-
+LL | |         if let Ok(_) = e.ok(4).as_ref() {
+   | |                        ^^^^^^^
+   | |                        |
+   | |                        this value will be stored in a temporary; let us call it `#2`
+   | |                        up until Edition 2021 `#2` is dropped last but will be dropped earlier in Edition 2024
+...  |
+LL | |     }, e.mark(2), e.ok(3));
+   | |                          -
+   | |                          |
+   | |                          now the temporary value is dropped here, before the local variables in the block or statement
+   | |__________________________this value will be stored in a temporary; let us call it `#1`
+   |                            `#1` will be dropped later as of Edition 2024
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+note: `#2` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+note: `#1` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+
+warning: relative drop order changing in Rust 2024
+  --> $DIR/drop-order-comparisons.rs:247:24
+   |
+LL |       _ = ({
+   |  _________-
+LL | |         if let Ok(_) = e.err(4).as_ref() {} else {
+   | |                        ^^^^^^^^
+   | |                        |
+   | |                        this value will be stored in a temporary; let us call it `#2`
+   | |                        up until Edition 2021 `#2` is dropped last but will be dropped earlier in Edition 2024
+...  |
+LL | |     }, e.mark(2), e.ok(3));
+   | |                          -
+   | |                          |
+   | |                          now the temporary value is dropped here, before the local variables in the block or statement
+   | |__________________________this value will be stored in a temporary; let us call it `#1`
+   |                            `#1` will be dropped later as of Edition 2024
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
+note: `#2` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+note: `#1` invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+
+warning: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/drop-order-comparisons.rs:123:13
+   |
+LL |     _ = (if let Ok(_) = e.ok(4).as_ref() {
+   |             ^^^^^^^^^^^^-------^^^^^^^^^
+   |                         |
+   |                         this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/drop-order-comparisons.rs:127:5
+   |
+LL |     }, e.mark(2), e.ok(3));
+   |     ^
+   = note: `#[warn(if_let_rescope)]` implied by `#[warn(rust_2024_compatibility)]`
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL ~     _ = (match e.ok(4).as_ref() { Ok(_) => {
+LL |
+LL |
+LL |             e.mark(1);
+LL ~     } _ => {}}, e.mark(2), e.ok(3));
+   |
+
+warning: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/drop-order-comparisons.rs:145:13
+   |
+LL |     _ = (if let Ok(_) = e.err(4).as_ref() {} else {
+   |             ^^^^^^^^^^^^--------^^^^^^^^^
+   |                         |
+   |                         this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/drop-order-comparisons.rs:145:44
+   |
+LL |     _ = (if let Ok(_) = e.err(4).as_ref() {} else {
+   |                                            ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL ~     _ = (match e.err(4).as_ref() { Ok(_) => {} _ => {
+LL |
+LL |
+LL |             e.mark(1);
+LL ~     }}, e.mark(2), e.ok(3));
+   |
+
+warning: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/drop-order-comparisons.rs:247:12
+   |
+LL |         if let Ok(_) = e.err(4).as_ref() {} else {
+   |            ^^^^^^^^^^^^--------^^^^^^^^^
+   |                        |
+   |                        this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/drop-order-comparisons.rs:247:43
+   |
+LL |         if let Ok(_) = e.err(4).as_ref() {} else {
+   |                                           ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL ~         match e.err(4).as_ref() { Ok(_) => {} _ => {
+LL |
+...
+LL |             e.mark(1);
+LL ~         }}
+   |
+
+warning: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/drop-order-comparisons.rs:352:12
+   |
+LL |         if let true = e.err(9).is_ok() {} else {
+   |            ^^^^^^^^^^^--------^^^^^^^^
+   |                       |
+   |                       this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/drop-order-comparisons.rs:352:41
+   |
+LL |         if let true = e.err(9).is_ok() {} else {
+   |                                         ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL ~         match e.err(9).is_ok() { true => {} _ => {
+LL |
+...
+LL |             e.mark(3);
+LL ~         }}}}}}}}};
+   |
+
+warning: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/drop-order-comparisons.rs:355:12
+   |
+LL |         if let Ok(_v) = e.err(8) {} else {
+   |            ^^^^^^^^^^^^^--------
+   |                         |
+   |                         this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/drop-order-comparisons.rs:355:35
+   |
+LL |         if let Ok(_v) = e.err(8) {} else {
+   |                                   ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL ~         match e.err(8) { Ok(_v) => {} _ => {
+LL |
+...
+LL |             e.mark(3);
+LL ~         }}}}}}}}};
+   |
+
+warning: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/drop-order-comparisons.rs:358:12
+   |
+LL |         if let Ok(_) = e.err(7) {} else {
+   |            ^^^^^^^^^^^^--------
+   |                        |
+   |                        this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/drop-order-comparisons.rs:358:34
+   |
+LL |         if let Ok(_) = e.err(7) {} else {
+   |                                  ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL ~         match e.err(7) { Ok(_) => {} _ => {
+LL |
+...
+LL |             e.mark(3);
+LL ~         }}}}}}}}};
+   |
+
+warning: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/drop-order-comparisons.rs:361:12
+   |
+LL |         if let Ok(_) = e.err(6).as_ref() {} else {
+   |            ^^^^^^^^^^^^--------^^^^^^^^^
+   |                        |
+   |                        this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/drop-order-comparisons.rs:361:43
+   |
+LL |         if let Ok(_) = e.err(6).as_ref() {} else {
+   |                                           ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL ~         match e.err(6).as_ref() { Ok(_) => {} _ => {
+LL |
+...
+LL |             e.mark(3);
+LL ~         }}}}}}}}};
+   |
+
+warning: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/drop-order-comparisons.rs:365:12
+   |
+LL |         if let Ok(_v) = e.err(5) {} else {
+   |            ^^^^^^^^^^^^^--------
+   |                         |
+   |                         this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/drop-order-comparisons.rs:365:35
+   |
+LL |         if let Ok(_v) = e.err(5) {} else {
+   |                                   ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL ~         match e.err(5) { Ok(_v) => {} _ => {
+LL |
+...
+LL |             e.mark(3);
+LL ~         }}}}}}}}};
+   |
+
+warning: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/drop-order-comparisons.rs:368:12
+   |
+LL |         if let Ok(_) = e.err(4) {} else {
+   |            ^^^^^^^^^^^^--------
+   |                        |
+   |                        this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/drop-order-comparisons.rs:368:34
+   |
+LL |         if let Ok(_) = e.err(4) {} else {
+   |                                  ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL ~         match e.err(4) { Ok(_) => {} _ => {
+LL |
+LL |
+LL |             e.mark(3);
+LL ~         }}}}}}}}};
+   |
+
+warning: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/drop-order-comparisons.rs:404:12
+   |
+LL |         if let Ok(_) = e.err(4).as_ref() {} else {
+   |            ^^^^^^^^^^^^--------^^^^^^^^^
+   |                        |
+   |                        this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/drop-order-comparisons.rs:404:43
+   |
+LL |         if let Ok(_) = e.err(4).as_ref() {} else {
+   |                                           ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL ~         match e.err(4).as_ref() { Ok(_) => {} _ => {
+LL |
+LL |
+LL |             e.mark(3);
+LL ~         }}}}}}}}};
+   |
+
+warning: 15 warnings emitted
+
diff --git a/tests/ui/drop/drop-order-comparisons.rs b/tests/ui/drop/drop-order-comparisons.rs
new file mode 100644
index 00000000000..78c75a9449f
--- /dev/null
+++ b/tests/ui/drop/drop-order-comparisons.rs
@@ -0,0 +1,575 @@
+// This tests various aspects of the drop order with a focus on:
+//
+// - The lifetime of temporaries with the `if let` construct (and with
+// various similar constructs) and how these lifetimes were shortened
+// for `if let` in Rust 2024.
+//
+// - The shortening of the lifetimes of temporaries in tail
+// expressions in Rust 2024.
+//
+// - The behavior of `let` chains and how this behavior compares to
+// nested `if let` expressions and chained `let .. else` statements.
+//
+// In the tests below, `Events` tracks a sequence of numbered events.
+// Calling `e.mark(..)` logs a numbered event immediately.  Calling
+// `e.ok(..)` or `e.err(..)` returns an `Ok(_)` or `Err(_)` value,
+// respectively, and logs the numbered event when that value is
+// dropped.  Calling `e.assert()` verifies that the correct number of
+// events were logged and that they were logged in the correct order.
+
+//@ revisions: e2021 e2024
+//@ [e2021] edition: 2021
+//@ [e2021] run-rustfix
+//@ [e2021] rustfix-only-machine-applicable
+//@ [e2024] edition: 2024
+//@ run-pass
+
+#![feature(let_chains)]
+#![cfg_attr(e2021, warn(rust_2024_compatibility))]
+
+fn t_bindings() {
+    let e = Events::new();
+    _ = {
+        e.mark(1);
+        let _v = e.ok(8);
+        let _v = e.ok(2).is_ok();
+        let _ = e.ok(3);
+        let Ok(_) = e.ok(4) else { unreachable!() };
+        let Ok(_) = e.ok(5).as_ref() else { unreachable!() };
+        let _v = e.ok(7);
+        e.mark(6);
+    };
+    e.assert(8);
+}
+
+fn t_tuples() {
+    let e = Events::new();
+    _ = (e.ok(1), e.ok(4).is_ok(), e.ok(2), e.ok(3).is_ok());
+    e.assert(4);
+}
+
+fn t_arrays() {
+    let e = Events::new();
+    trait Tr {}
+    impl<T> Tr for T {}
+    fn b<'a, T: 'a>(x: T) -> Box<dyn Tr + 'a> {
+        Box::new(x)
+    }
+    _ = [b(e.ok(1)), b(e.ok(4).is_ok()), b(e.ok(2)), b(e.ok(3).is_ok())];
+    e.assert(4);
+}
+
+fn t_fncalls() {
+    let e = Events::new();
+    let f = |_, _, _, _| {};
+    _ = f(e.ok(2), e.ok(4).is_ok(), e.ok(1), e.ok(3).is_ok());
+    e.assert(4);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_tailexpr_bindings() {
+    let e = Events::new();
+    _ = ({
+        let _v = e.ok(2);
+        let _v = e.ok(1);
+        e.ok(5).is_ok()
+        //[e2021]~^ WARN relative drop order changing in Rust 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+    }, e.mark(3), e.ok(4));
+    e.assert(5);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_tailexpr_bindings() {
+    let e = Events::new();
+    _ = ({
+        let _v = e.ok(3);
+        let _v = e.ok(2);
+        e.ok(1).is_ok()
+    }, e.mark(4), e.ok(5));
+    e.assert(5);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_tailexpr_tuples() {
+    let e = Events::new();
+    _ = ({
+        (e.ok(2), e.ok(6).is_ok(), e.ok(3), e.ok(5).is_ok())
+        //[e2021]~^ WARN relative drop order changing in Rust 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        //[e2021]~| WARN relative drop order changing in Rust 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+    }, e.mark(1), e.ok(4));
+    e.assert(6);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_tailexpr_tuples() {
+    let e = Events::new();
+    _ = ({
+        (e.ok(4), e.ok(2).is_ok(), e.ok(5), e.ok(1).is_ok())
+    }, e.mark(3), e.ok(6));
+    e.assert(6);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_then() {
+    let e = Events::new();
+    _ = (if let Ok(_) = e.ok(4).as_ref() {
+            //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(1);
+    }, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_then() {
+    let e = Events::new();
+    _ = (if let Ok(_) = e.ok(2).as_ref() {
+            e.mark(1);
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_else() {
+    let e = Events::new();
+    _ = (if let Ok(_) = e.err(4).as_ref() {} else {
+            //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(1);
+    }, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_else() {
+    let e = Events::new();
+    _ = (if let Ok(_) = e.err(1).as_ref() {} else {
+            e.mark(2);
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[rustfmt::skip]
+fn t_match_then() {
+    let e = Events::new();
+    _ = (match e.ok(4).as_ref() {
+            Ok(_) => e.mark(1),
+            _ => unreachable!(),
+    }, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[rustfmt::skip]
+fn t_match_else() {
+    let e = Events::new();
+    _ = (match e.err(4).as_ref() {
+            Ok(_) => unreachable!(),
+            _ => e.mark(1),
+    }, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[rustfmt::skip]
+fn t_let_else_then() {
+    let e = Events::new();
+    _ = ('top: {
+         'chain: {
+            let Ok(_) = e.ok(1).as_ref() else { break 'chain };
+            // The "then" branch:
+            e.mark(2);
+            break 'top;
+        }
+        // The "else" branch:
+        unreachable!()
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[rustfmt::skip]
+fn t_let_else_else() {
+    let e = Events::new();
+    _ = ('top: {
+         'chain: {
+            let Ok(_) = e.err(1).as_ref() else { break 'chain };
+            // The "then" branch:
+            unreachable!();
+            #[allow(unreachable_code)]
+            break 'top;
+        }
+        // The "else" branch:
+        e.mark(2);
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_then_tailexpr() {
+    let e = Events::new();
+    _ = ({
+        if let Ok(_) = e.ok(4).as_ref() {
+            //[e2021]~^ WARN relative drop order changing in Rust 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(1);
+        }
+    }, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_then_tailexpr() {
+    let e = Events::new();
+    _ = ({
+        if let Ok(_) = e.ok(2).as_ref() {
+            e.mark(1);
+        }
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_else_tailexpr() {
+    let e = Events::new();
+    _ = ({
+        if let Ok(_) = e.err(4).as_ref() {} else {
+            //[e2021]~^ WARN relative drop order changing in Rust 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            //[e2021]~| WARN if let` assigns a shorter lifetime since Edition 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(1);
+        }
+    }, e.mark(2), e.ok(3));
+    e.assert(4);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_else_tailexpr() {
+    let e = Events::new();
+    _ = ({
+        if let Ok(_) = e.err(1).as_ref() {} else {
+            e.mark(2);
+        }
+    }, e.mark(3), e.ok(4));
+    e.assert(4);
+}
+
+#[rustfmt::skip]
+fn t_if_let_nested_then() {
+    let e = Events::new();
+    _ = {
+        // The unusual formatting, here and below, is to make the
+        // comparison with `let` chains more direct.
+        if e.ok(1).is_ok() {
+        if let true = e.ok(9).is_ok() {
+        if let Ok(_v) = e.ok(8) {
+        if let Ok(_) = e.ok(7) {
+        if let Ok(_) = e.ok(6).as_ref() {
+        if e.ok(2).is_ok() {
+        if let Ok(_v) = e.ok(5) {
+        if let Ok(_) = e.ok(4).as_ref() {
+            e.mark(3);
+        }}}}}}}}
+    };
+    e.assert(9);
+}
+
+#[rustfmt::skip]
+fn t_let_else_chained_then() {
+    let e = Events::new();
+    _ = 'top: {
+        'chain: {
+            if e.ok(1).is_ok() {} else { break 'chain };
+            let true = e.ok(2).is_ok() else { break 'chain };
+            let Ok(_v) = e.ok(9) else { break 'chain };
+            let Ok(_) = e.ok(3) else { break 'chain };
+            let Ok(_) = e.ok(4).as_ref() else { break 'chain };
+            if e.ok(5).is_ok() {} else { break 'chain };
+            let Ok(_v) = e.ok(8) else { break 'chain };
+            let Ok(_) = e.ok(6).as_ref() else { break 'chain };
+            // The "then" branch:
+            e.mark(7);
+            break 'top;
+        }
+        // The "else" branch:
+        unreachable!()
+    };
+    e.assert(9);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_chains_then() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok()
+        && let true = e.ok(9).is_ok()
+        && let Ok(_v) = e.ok(5)
+        && let Ok(_) = e.ok(8)
+        && let Ok(_) = e.ok(7).as_ref()
+        && e.ok(2).is_ok()
+        && let Ok(_v) = e.ok(4)
+        && let Ok(_) = e.ok(6).as_ref() {
+            e.mark(3);
+        };
+    e.assert(9);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_chains_then() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok()
+        && let true = e.ok(9).is_ok()
+        && let Ok(_v) = e.ok(8)
+        && let Ok(_) = e.ok(7)
+        && let Ok(_) = e.ok(6).as_ref()
+        && e.ok(2).is_ok()
+        && let Ok(_v) = e.ok(5)
+        && let Ok(_) = e.ok(4).as_ref() {
+            e.mark(3);
+        };
+    e.assert(9);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_nested_else() {
+    let e = Events::new();
+    _ = if e.err(1).is_ok() {} else {
+        if let true = e.err(9).is_ok() {} else {
+        //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        if let Ok(_v) = e.err(8) {} else {
+        //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        if let Ok(_) = e.err(7) {} else {
+        //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        if let Ok(_) = e.err(6).as_ref() {} else {
+        //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        if e.err(2).is_ok() {} else {
+        if let Ok(_v) = e.err(5) {} else {
+        //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+        //[e2021]~| WARN this changes meaning in Rust 2024
+        if let Ok(_) = e.err(4) {} else {
+            //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(3);
+        }}}}}}}};
+    e.assert(9);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_nested_else() {
+    let e = Events::new();
+    _ = if e.err(1).is_ok() {} else {
+        if let true = e.err(2).is_ok() {} else {
+        if let Ok(_v) = e.err(3) {} else {
+        if let Ok(_) = e.err(4) {} else {
+        if let Ok(_) = e.err(5).as_ref() {} else {
+        if e.err(6).is_ok() {} else {
+        if let Ok(_v) = e.err(7) {} else {
+        if let Ok(_) = e.err(8) {} else {
+            e.mark(9);
+        }}}}}}}};
+    e.assert(9);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_nested_then_else() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok() {
+        if let true = e.ok(9).is_ok() {
+        if let Ok(_v) = e.ok(8) {
+        if let Ok(_) = e.ok(7) {
+        if let Ok(_) = e.ok(6).as_ref() {
+        if e.ok(2).is_ok() {
+        if let Ok(_v) = e.ok(5) {
+        if let Ok(_) = e.err(4).as_ref() {} else {
+            //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024
+            //[e2021]~| WARN this changes meaning in Rust 2024
+            e.mark(3);
+        }}}}}}}};
+    e.assert(9);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_nested_then_else() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok() {
+        if let true = e.ok(9).is_ok() {
+        if let Ok(_v) = e.ok(8) {
+        if let Ok(_) = e.ok(7) {
+        if let Ok(_) = e.ok(6).as_ref() {
+        if e.ok(2).is_ok() {
+        if let Ok(_v) = e.ok(5) {
+        if let Ok(_) = e.err(3).as_ref() {} else {
+            e.mark(4);
+        }}}}}}}};
+    e.assert(9);
+}
+
+#[rustfmt::skip]
+fn t_let_else_chained_then_else() {
+    let e = Events::new();
+    _ = 'top: {
+        'chain: {
+            if e.ok(1).is_ok() {} else { break 'chain };
+            let true = e.ok(2).is_ok() else { break 'chain };
+            let Ok(_v) = e.ok(8) else { break 'chain };
+            let Ok(_) = e.ok(3) else { break 'chain };
+            let Ok(_) = e.ok(4).as_ref() else { break 'chain };
+            if e.ok(5).is_ok() {} else { break 'chain };
+            let Ok(_v) = e.ok(7) else { break 'chain };
+            let Ok(_) = e.err(6).as_ref() else { break 'chain };
+            // The "then" branch:
+            unreachable!();
+            #[allow(unreachable_code)]
+            break 'top;
+        }
+        // The "else" branch:
+        e.mark(9);
+    };
+    e.assert(9);
+}
+
+#[cfg(e2021)]
+#[rustfmt::skip]
+fn t_if_let_chains_then_else() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok()
+        && let true = e.ok(9).is_ok()
+        && let Ok(_v) = e.ok(4)
+        && let Ok(_) = e.ok(8)
+        && let Ok(_) = e.ok(7).as_ref()
+        && e.ok(2).is_ok()
+        && let Ok(_v) = e.ok(3)
+        && let Ok(_) = e.err(6) {} else {
+            e.mark(5);
+        };
+    e.assert(9);
+}
+
+#[cfg(e2024)]
+#[rustfmt::skip]
+fn t_if_let_chains_then_else() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok()
+        && let true = e.ok(8).is_ok()
+        && let Ok(_v) = e.ok(7)
+        && let Ok(_) = e.ok(6)
+        && let Ok(_) = e.ok(5).as_ref()
+        && e.ok(2).is_ok()
+        && let Ok(_v) = e.ok(4)
+        && let Ok(_) = e.err(3) {} else {
+            e.mark(9);
+        };
+    e.assert(9);
+}
+
+fn main() {
+    t_bindings();
+    t_tuples();
+    t_arrays();
+    t_fncalls();
+    t_tailexpr_bindings();
+    t_tailexpr_tuples();
+    t_if_let_then();
+    t_if_let_else();
+    t_match_then();
+    t_match_else();
+    t_let_else_then();
+    t_let_else_else();
+    t_if_let_then_tailexpr();
+    t_if_let_else_tailexpr();
+    t_if_let_nested_then();
+    t_let_else_chained_then();
+    t_if_let_chains_then();
+    t_if_let_nested_else();
+    t_if_let_nested_then_else();
+    t_let_else_chained_then_else();
+    t_if_let_chains_then_else();
+}
+
+// # Test scaffolding
+
+use core::cell::RefCell;
+use std::collections::HashSet;
+
+/// A buffer to track the order of events.
+///
+/// First, numbered events are logged into this buffer.
+///
+/// Then, `assert` is called to verify that the correct number of
+/// events were logged, and that they were logged in the expected
+/// order.
+struct Events(RefCell<Option<Vec<u64>>>);
+
+impl Events {
+    const fn new() -> Self {
+        Self(RefCell::new(Some(Vec::new())))
+    }
+    #[track_caller]
+    fn assert(&self, max: u64) {
+        let buf = &self.0;
+        let v1 = buf.borrow().as_ref().unwrap().clone();
+        let mut v2 = buf.borrow().as_ref().unwrap().clone();
+        *buf.borrow_mut() = None;
+        v2.sort();
+        let uniq_len = v2.iter().collect::<HashSet<_>>().len();
+        // Check that the sequence is sorted.
+        assert_eq!(v1, v2);
+        // Check that there are no duplicates.
+        assert_eq!(v2.len(), uniq_len);
+        // Check that the length is the expected one.
+        assert_eq!(max, uniq_len as u64);
+        // Check that the last marker is the expected one.
+        assert_eq!(v2.last().unwrap(), &max);
+    }
+    /// Return an `Ok` value that logs its drop.
+    fn ok(&self, m: u64) -> Result<LogDrop<'_>, LogDrop<'_>> {
+        Ok(LogDrop(self, m))
+    }
+    /// Return an `Err` value that logs its drop.
+    fn err(&self, m: u64) -> Result<LogDrop, LogDrop> {
+        Err(LogDrop(self, m))
+    }
+    /// Log an event.
+    fn mark(&self, m: u64) {
+        self.0.borrow_mut().as_mut().unwrap().push(m);
+    }
+}
+
+impl Drop for Events {
+    fn drop(&mut self) {
+        if self.0.borrow().is_some() {
+            panic!("failed to call `Events::assert()`");
+        }
+    }
+}
+
+/// A type that logs its drop events.
+struct LogDrop<'b>(&'b Events, u64);
+
+impl<'b> Drop for LogDrop<'b> {
+    fn drop(&mut self) {
+        self.0.mark(self.1);
+    }
+}
diff --git a/tests/ui/drop/lint-if-let-rescope-with-macro.stderr b/tests/ui/drop/lint-if-let-rescope-with-macro.stderr
index d73a878c74f..029d5c74929 100644
--- a/tests/ui/drop/lint-if-let-rescope-with-macro.stderr
+++ b/tests/ui/drop/lint-if-let-rescope-with-macro.stderr
@@ -2,7 +2,7 @@ error: `if let` assigns a shorter lifetime since Edition 2024
   --> $DIR/lint-if-let-rescope-with-macro.rs:12:12
    |
 LL |           if let $p = $e { $($conseq)* } else { $($alt)* }
-   |              ^^^
+   |              ^^^^^^^^^^^
 ...
 LL | /     edition_2021_if_let! {
 LL | |         Some(_value),
diff --git a/tests/ui/duplicate/dupe-symbols-7.stderr b/tests/ui/duplicate/dupe-symbols-7.stderr
index ab9167e005a..aa6213af2e4 100644
--- a/tests/ui/duplicate/dupe-symbols-7.stderr
+++ b/tests/ui/duplicate/dupe-symbols-7.stderr
@@ -4,7 +4,7 @@ error: entry symbol `main` declared multiple times
 LL | fn main(){}
    | ^^^^^^^^^
    |
-   = help: did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead
+   = help: did you use `#[no_mangle]` on `fn main`? Use `#![no_main]` to suppress the usual Rust-generated entry point
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/duplicate/dupe-symbols-8.stderr b/tests/ui/duplicate/dupe-symbols-8.stderr
index d7d419c9aa4..0f47d3683b5 100644
--- a/tests/ui/duplicate/dupe-symbols-8.stderr
+++ b/tests/ui/duplicate/dupe-symbols-8.stderr
@@ -4,7 +4,7 @@ error: entry symbol `main` declared multiple times
 LL | fn main() {
    | ^^^^^^^^^
    |
-   = help: did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead
+   = help: did you use `#[no_mangle]` on `fn main`? Use `#![no_main]` to suppress the usual Rust-generated entry point
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/dyn-compatibility/almost-supertrait-associated-type.rs b/tests/ui/dyn-compatibility/almost-supertrait-associated-type.rs
index 83076f7d5fc..1b1b8bcf03d 100644
--- a/tests/ui/dyn-compatibility/almost-supertrait-associated-type.rs
+++ b/tests/ui/dyn-compatibility/almost-supertrait-associated-type.rs
@@ -5,8 +5,8 @@ use std::marker::PhantomData;
 
 fn transmute<T, U>(t: T) -> U {
     (&PhantomData::<T> as &dyn Foo<T, U>).transmute(t)
-    //~^ ERROR the trait `Foo` cannot be made into an object
-    //~| ERROR the trait `Foo` cannot be made into an object
+    //~^ ERROR the trait `Foo` is not dyn compatible
+    //~| ERROR the trait `Foo` is not dyn compatible
 }
 
 struct ActuallySuper;
@@ -19,7 +19,7 @@ trait Dyn {
     type Out;
 }
 impl<T, U> Dyn for dyn Foo<T, U> + '_ {
-//~^ ERROR the trait `Foo` cannot be made into an object
+//~^ ERROR the trait `Foo` is not dyn compatible
     type Out = U;
 }
 impl<S: Dyn<Out = U> + ?Sized, U> Super<NotActuallySuper> for S {
diff --git a/tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr b/tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr
index 99bcccc20c0..f241333f2a7 100644
--- a/tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr
+++ b/tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr
@@ -1,53 +1,53 @@
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/almost-supertrait-associated-type.rs:21:20
    |
 LL | impl<T, U> Dyn for dyn Foo<T, U> + '_ {
-   |                    ^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |                    ^^^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/almost-supertrait-associated-type.rs:33:34
    |
 LL | trait Foo<T, U>: Super<ActuallySuper, Assoc = T>
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 ...
 LL |     fn transmute(&self, t: T) -> <Self as Super<NotActuallySuper>>::Assoc;
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `transmute` references the `Self` type in its return type
    = help: consider moving `transmute` to another trait
-   = help: only type `std::marker::PhantomData<T>` implements the trait, consider using it directly instead
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/almost-supertrait-associated-type.rs:7:27
    |
 LL |     (&PhantomData::<T> as &dyn Foo<T, U>).transmute(t)
-   |                           ^^^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |                           ^^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/almost-supertrait-associated-type.rs:33:34
    |
 LL | trait Foo<T, U>: Super<ActuallySuper, Assoc = T>
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 ...
 LL |     fn transmute(&self, t: T) -> <Self as Super<NotActuallySuper>>::Assoc;
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `transmute` references the `Self` type in its return type
    = help: consider moving `transmute` to another trait
-   = help: only type `std::marker::PhantomData<T>` implements the trait, consider using it directly instead
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/almost-supertrait-associated-type.rs:7:6
    |
 LL |     (&PhantomData::<T> as &dyn Foo<T, U>).transmute(t)
-   |      ^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |      ^^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/almost-supertrait-associated-type.rs:33:34
    |
 LL | trait Foo<T, U>: Super<ActuallySuper, Assoc = T>
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 ...
 LL |     fn transmute(&self, t: T) -> <Self as Super<NotActuallySuper>>::Assoc;
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `transmute` references the `Self` type in its return type
    = help: consider moving `transmute` to another trait
-   = help: only type `std::marker::PhantomData<T>` implements the trait, consider using it directly instead
    = note: required for the cast from `&PhantomData<T>` to `&dyn Foo<T, U>`
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/dyn-compatibility/associated-consts.curr.stderr b/tests/ui/dyn-compatibility/associated-consts.curr.stderr
index 17d184942c7..45d4f795542 100644
--- a/tests/ui/dyn-compatibility/associated-consts.curr.stderr
+++ b/tests/ui/dyn-compatibility/associated-consts.curr.stderr
@@ -1,29 +1,31 @@
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/associated-consts.rs:12:31
    |
 LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-   |                               ^^^^^^^ `Bar` cannot be made into an object
+   |                               ^^^^^^^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/associated-consts.rs:9:11
    |
 LL | trait Bar {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     const X: usize;
    |           ^ ...because it contains this associated `const`
    = help: consider moving `X` to another trait
 
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/associated-consts.rs:14:5
    |
 LL |     t
-   |     ^ `Bar` cannot be made into an object
+   |     ^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/associated-consts.rs:9:11
    |
 LL | trait Bar {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     const X: usize;
    |           ^ ...because it contains this associated `const`
    = help: consider moving `X` to another trait
diff --git a/tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr
index cc5120232c2..4c8c82196ed 100644
--- a/tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr
@@ -1,14 +1,15 @@
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/associated-consts.rs:14:5
    |
 LL |     t
-   |     ^ `Bar` cannot be made into an object
+   |     ^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/associated-consts.rs:9:11
    |
 LL | trait Bar {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     const X: usize;
    |           ^ ...because it contains this associated `const`
    = help: consider moving `X` to another trait
diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr
index 54daefea31c..ff5e9fdb6b3 100644
--- a/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr
+++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr
@@ -26,14 +26,15 @@ help: if this is a dyn-compatible trait, use `dyn`
 LL | fn id<F>(f: dyn Copy) -> usize {
    |             +++
 
-error[E0038]: the trait `Copy` cannot be made into an object
+error[E0038]: the trait `Copy` is not dyn compatible
   --> $DIR/avoid-ice-on-warning-2.rs:4:13
    |
 LL | fn id<F>(f: Copy) -> usize {
-   |             ^^^^ `Copy` cannot be made into an object
+   |             ^^^^ `Copy` is not dyn compatible
    |
-   = note: the trait cannot be made into an object because it requires `Self: Sized`
-   = note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+   = note: the trait is not dyn compatible because it requires `Self: Sized`
+   = note: for a trait to be dyn compatible it needs to allow building a vtable
+           for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
 
 error[E0618]: expected function, found `(dyn Copy + 'static)`
   --> $DIR/avoid-ice-on-warning-2.rs:12:5
diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.rs b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.rs
index 3c2da667b39..312e0d666f1 100644
--- a/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.rs
+++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.rs
@@ -3,7 +3,7 @@
 //@[new] edition:2021
 fn id<F>(f: Copy) -> usize {
 //[new]~^ ERROR expected a type, found a trait
-//[old]~^^ ERROR the trait `Copy` cannot be made into an object
+//[old]~^^ ERROR the trait `Copy` is not dyn compatible
 //[old]~| ERROR the size for values of type `(dyn Copy + 'static)`
 //[old]~| WARN trait objects without an explicit `dyn` are deprecated
 //[old]~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr
index 6bc2d73a0d0..92a2d340115 100644
--- a/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr
+++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr
@@ -65,19 +65,20 @@ help: if this is a dyn-compatible trait, use `dyn`
 LL | trait B { fn f(a: dyn A) -> A; }
    |                   +++
 
-error[E0038]: the trait `A` cannot be made into an object
+error[E0038]: the trait `A` is not dyn compatible
   --> $DIR/avoid-ice-on-warning-3.rs:4:19
    |
 LL | trait B { fn f(a: A) -> A; }
-   |                   ^ `A` cannot be made into an object
+   |                   ^ `A` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/avoid-ice-on-warning-3.rs:14:14
    |
 LL | trait A { fn g(b: B) -> B; }
    |       -      ^ ...because associated function `g` has no `self` parameter
    |       |
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
 help: consider turning `g` into a method by giving it a `&self` argument
    |
 LL | trait A { fn g(&self, b: B) -> B; }
@@ -101,19 +102,20 @@ help: if this is a dyn-compatible trait, use `dyn`
 LL | trait A { fn g(b: dyn B) -> B; }
    |                   +++
 
-error[E0038]: the trait `B` cannot be made into an object
+error[E0038]: the trait `B` is not dyn compatible
   --> $DIR/avoid-ice-on-warning-3.rs:14:19
    |
 LL | trait A { fn g(b: B) -> B; }
-   |                   ^ `B` cannot be made into an object
+   |                   ^ `B` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/avoid-ice-on-warning-3.rs:4:14
    |
 LL | trait B { fn f(a: A) -> A; }
    |       -      ^ ...because associated function `f` has no `self` parameter
    |       |
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
 help: consider turning `f` into a method by giving it a `&self` argument
    |
 LL | trait B { fn f(&self, a: A) -> A; }
diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.rs b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.rs
index 00d47225e92..9ccbfc15a0d 100644
--- a/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.rs
+++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.rs
@@ -4,7 +4,7 @@
 trait B { fn f(a: A) -> A; }
 //[new]~^ ERROR expected a type, found a trait
 //[new]~| ERROR expected a type, found a trait
-//[old]~^^^ ERROR the trait `A` cannot be made into an object
+//[old]~^^^ ERROR the trait `A` is not dyn compatible
 //[old]~| WARN trait objects without an explicit `dyn` are deprecated
 //[old]~| WARN trait objects without an explicit `dyn` are deprecated
 //[old]~| WARN trait objects without an explicit `dyn` are deprecated
@@ -14,7 +14,7 @@ trait B { fn f(a: A) -> A; }
 trait A { fn g(b: B) -> B; }
 //[new]~^ ERROR expected a type, found a trait
 //[new]~| ERROR expected a type, found a trait
-//[old]~^^^ ERROR the trait `B` cannot be made into an object
+//[old]~^^^ ERROR the trait `B` is not dyn compatible
 //[old]~| WARN trait objects without an explicit `dyn` are deprecated
 //[old]~| WARN trait objects without an explicit `dyn` are deprecated
 //[old]~| WARN trait objects without an explicit `dyn` are deprecated
diff --git a/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.new.fixed b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.new.fixed
index a54892afd3e..b5200e9fff5 100644
--- a/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.new.fixed
+++ b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.new.fixed
@@ -5,7 +5,7 @@
 #![deny(bare_trait_objects)]
 fn ord_prefer_dot(s: String) -> impl Ord {
     //[new]~^ ERROR expected a type, found a trait
-    //[old]~^^ ERROR the trait `Ord` cannot be made into an object
+    //[old]~^^ ERROR the trait `Ord` is not dyn compatible
     //[old]~| ERROR trait objects without an explicit `dyn` are deprecated
     //[old]~| WARNING this is accepted in the current edition (Rust 2015)
     (s.starts_with("."), s)
diff --git a/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr
index 45c9b0ce5d9..e3ec5b9c3c8 100644
--- a/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr
+++ b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr
@@ -16,19 +16,20 @@ help: if this is a dyn-compatible trait, use `dyn`
 LL | fn ord_prefer_dot(s: String) -> dyn Ord {
    |                                 +++
 
-error[E0038]: the trait `Ord` cannot be made into an object
+error[E0038]: the trait `Ord` is not dyn compatible
   --> $DIR/bare-trait-dont-suggest-dyn.rs:6:33
    |
 LL | fn ord_prefer_dot(s: String) -> Ord {
-   |                                 ^^^ `Ord` cannot be made into an object
+   |                                 ^^^ `Ord` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $SRC_DIR/core/src/cmp.rs:LL:COL
    |
-   = note: the trait cannot be made into an object because it uses `Self` as a type parameter
+   = note: the trait is not dyn compatible because it uses `Self` as a type parameter
   ::: $SRC_DIR/core/src/cmp.rs:LL:COL
    |
-   = note: the trait cannot be made into an object because it uses `Self` as a type parameter
+   = note: the trait is not dyn compatible because it uses `Self` as a type parameter
 help: consider using an opaque type instead
    |
 LL | fn ord_prefer_dot(s: String) -> impl Ord {
diff --git a/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.rs b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.rs
index cf9be612d2e..385fd48102c 100644
--- a/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.rs
+++ b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.rs
@@ -5,7 +5,7 @@
 #![deny(bare_trait_objects)]
 fn ord_prefer_dot(s: String) -> Ord {
     //[new]~^ ERROR expected a type, found a trait
-    //[old]~^^ ERROR the trait `Ord` cannot be made into an object
+    //[old]~^^ ERROR the trait `Ord` is not dyn compatible
     //[old]~| ERROR trait objects without an explicit `dyn` are deprecated
     //[old]~| WARNING this is accepted in the current edition (Rust 2015)
     (s.starts_with("."), s)
diff --git a/tests/ui/dyn-compatibility/bounds.rs b/tests/ui/dyn-compatibility/bounds.rs
index 1e04d11c516..ed4a69129af 100644
--- a/tests/ui/dyn-compatibility/bounds.rs
+++ b/tests/ui/dyn-compatibility/bounds.rs
@@ -5,7 +5,7 @@ trait X {
 }
 
 fn f() -> Box<dyn X<U = u32>> {
-    //~^ ERROR the trait `X` cannot be made into an object
+    //~^ ERROR the trait `X` is not dyn compatible
     loop {}
 }
 
diff --git a/tests/ui/dyn-compatibility/bounds.stderr b/tests/ui/dyn-compatibility/bounds.stderr
index 9231d524fd1..d45e66b1d5e 100644
--- a/tests/ui/dyn-compatibility/bounds.stderr
+++ b/tests/ui/dyn-compatibility/bounds.stderr
@@ -1,14 +1,15 @@
-error[E0038]: the trait `X` cannot be made into an object
+error[E0038]: the trait `X` is not dyn compatible
   --> $DIR/bounds.rs:7:15
    |
 LL | fn f() -> Box<dyn X<U = u32>> {
-   |               ^^^^^^^^^^^^^^ `X` cannot be made into an object
+   |               ^^^^^^^^^^^^^^ `X` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/bounds.rs:4:13
    |
 LL | trait X {
-   |       - this trait cannot be made into an object...
+   |       - this trait is not dyn compatible...
 LL |     type U: PartialEq<Self>;
    |             ^^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter
 
diff --git a/tests/ui/dyn-compatibility/gat-incompatible-supertrait.rs b/tests/ui/dyn-compatibility/gat-incompatible-supertrait.rs
new file mode 100644
index 00000000000..fff29ac2b51
--- /dev/null
+++ b/tests/ui/dyn-compatibility/gat-incompatible-supertrait.rs
@@ -0,0 +1,18 @@
+// Test that the dyn-compatibility diagnostics for GATs refer first to the
+// user-named trait, not the GAT-containing supertrait.
+//
+// NOTE: this test is currently broken, and first reports:
+// "the trait `Super` is not dyn compatible"
+//
+//@ edition:2018
+
+trait Super {
+    type Assoc<'a>;
+}
+
+trait Child: Super {}
+
+fn take_dyn(_: &dyn Child) {}
+//~^ ERROR the trait `Super` is not dyn compatible
+
+fn main() {}
diff --git a/tests/ui/dyn-compatibility/gat-incompatible-supertrait.stderr b/tests/ui/dyn-compatibility/gat-incompatible-supertrait.stderr
new file mode 100644
index 00000000000..04dc0b1d6f4
--- /dev/null
+++ b/tests/ui/dyn-compatibility/gat-incompatible-supertrait.stderr
@@ -0,0 +1,19 @@
+error[E0038]: the trait `Super` is not dyn compatible
+  --> $DIR/gat-incompatible-supertrait.rs:15:21
+   |
+LL | fn take_dyn(_: &dyn Child) {}
+   |                     ^^^^^ `Super` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/gat-incompatible-supertrait.rs:10:10
+   |
+LL | trait Super {
+   |       ----- this trait is not dyn compatible...
+LL |     type Assoc<'a>;
+   |          ^^^^^ ...because it contains the generic associated type `Assoc`
+   = help: consider moving `Assoc` to another trait
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/dyn-compatibility/generics.curr.stderr b/tests/ui/dyn-compatibility/generics.curr.stderr
index c63db38a080..1607954ab70 100644
--- a/tests/ui/dyn-compatibility/generics.curr.stderr
+++ b/tests/ui/dyn-compatibility/generics.curr.stderr
@@ -1,75 +1,80 @@
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/generics.rs:18:31
    |
 LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-   |                               ^^^^^^^ `Bar` cannot be made into an object
+   |                               ^^^^^^^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/generics.rs:10:8
    |
 LL | trait Bar {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn bar<T>(&self, t: T);
    |        ^^^ ...because method `bar` has generic type parameters
    = help: consider moving `bar` to another trait
 
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/generics.rs:25:40
    |
 LL | fn make_bar_explicit<T:Bar>(t: &T) -> &dyn Bar {
-   |                                        ^^^^^^^ `Bar` cannot be made into an object
+   |                                        ^^^^^^^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/generics.rs:10:8
    |
 LL | trait Bar {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn bar<T>(&self, t: T);
    |        ^^^ ...because method `bar` has generic type parameters
    = help: consider moving `bar` to another trait
 
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/generics.rs:20:5
    |
 LL |     t
-   |     ^ `Bar` cannot be made into an object
+   |     ^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/generics.rs:10:8
    |
 LL | trait Bar {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn bar<T>(&self, t: T);
    |        ^^^ ...because method `bar` has generic type parameters
    = help: consider moving `bar` to another trait
    = note: required for the cast from `&T` to `&dyn Bar`
 
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/generics.rs:27:10
    |
 LL |     t as &dyn Bar
-   |          ^^^^^^^^ `Bar` cannot be made into an object
+   |          ^^^^^^^^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/generics.rs:10:8
    |
 LL | trait Bar {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn bar<T>(&self, t: T);
    |        ^^^ ...because method `bar` has generic type parameters
    = help: consider moving `bar` to another trait
 
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/generics.rs:27:5
    |
 LL |     t as &dyn Bar
-   |     ^ `Bar` cannot be made into an object
+   |     ^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/generics.rs:10:8
    |
 LL | trait Bar {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn bar<T>(&self, t: T);
    |        ^^^ ...because method `bar` has generic type parameters
    = help: consider moving `bar` to another trait
diff --git a/tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr
index ba2546ef2dc..7f31b29b39c 100644
--- a/tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr
@@ -1,30 +1,32 @@
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/generics.rs:20:5
    |
 LL |     t
-   |     ^ `Bar` cannot be made into an object
+   |     ^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/generics.rs:10:8
    |
 LL | trait Bar {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn bar<T>(&self, t: T);
    |        ^^^ ...because method `bar` has generic type parameters
    = help: consider moving `bar` to another trait
    = note: required for the cast from `&T` to `&dyn Bar`
 
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/generics.rs:27:5
    |
 LL |     t as &dyn Bar
-   |     ^ `Bar` cannot be made into an object
+   |     ^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/generics.rs:10:8
    |
 LL | trait Bar {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn bar<T>(&self, t: T);
    |        ^^^ ...because method `bar` has generic type parameters
    = help: consider moving `bar` to another trait
diff --git a/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr b/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr
index 7378ec023c9..1ed78e1e659 100644
--- a/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr
+++ b/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr
@@ -1,36 +1,38 @@
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/mention-correct-dyn-incompatible-trait.rs:19:15
    |
 LL |     let test: &mut dyn Bar = &mut thing;
-   |               ^^^^^^^^^^^^ `Bar` cannot be made into an object
+   |               ^^^^^^^^^^^^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/mention-correct-dyn-incompatible-trait.rs:4:8
    |
 LL |     fn foo<T>(&self, val: T);
    |        ^^^ ...because method `foo` has generic type parameters
 ...
 LL | trait Bar: Foo { }
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
    = help: consider moving `foo` to another trait
-   = help: only type `Thing` implements the trait, consider using it directly instead
+   = help: only type `Thing` implements `Bar`; consider using it directly instead.
 
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/mention-correct-dyn-incompatible-trait.rs:19:30
    |
 LL |     let test: &mut dyn Bar = &mut thing;
-   |                              ^^^^^^^^^^ `Bar` cannot be made into an object
+   |                              ^^^^^^^^^^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/mention-correct-dyn-incompatible-trait.rs:4:8
    |
 LL |     fn foo<T>(&self, val: T);
    |        ^^^ ...because method `foo` has generic type parameters
 ...
 LL | trait Bar: Foo { }
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
    = help: consider moving `foo` to another trait
-   = help: only type `Thing` implements the trait, consider using it directly instead
+   = help: only type `Thing` implements `Bar`; consider using it directly instead.
    = note: required for the cast from `&mut Thing` to `&mut dyn Bar`
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.rs b/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.rs
index c9ec44cc0b8..2ab0c6c8f5d 100644
--- a/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.rs
+++ b/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.rs
@@ -36,9 +36,9 @@ impl <'x> Expr for SExpr<'x> {
 
 fn main() {
     let a: Box<dyn Expr> = Box::new(SExpr::new());
-    //~^ ERROR: `Expr` cannot be made into an object
+    //~^ ERROR: `Expr` is not dyn compatible
     let b: Box<dyn Expr> = Box::new(SExpr::new());
-    //~^ ERROR: `Expr` cannot be made into an object
+    //~^ ERROR: `Expr` is not dyn compatible
 
     // assert_eq!(a , b);
 }
diff --git a/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.stderr b/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.stderr
index 7578edce7d1..eba2c15dd74 100644
--- a/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.stderr
+++ b/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.stderr
@@ -1,47 +1,47 @@
-error[E0038]: the trait `Expr` cannot be made into an object
-  --> $DIR/mentions-Self-in-super-predicates.rs:12:23
+error[E0038]: the trait `Expr` is not dyn compatible
+  --> $DIR/mentions-Self-in-super-predicates.rs:12:27
    |
 LL |     elements: Vec<Box<dyn Expr + 'x>>,
-   |                       ^^^^^^^^^^^^^ `Expr` cannot be made into an object
+   |                           ^^^^ `Expr` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/mentions-Self-in-super-predicates.rs:5:21
    |
 LL | trait Expr: Debug + PartialEq {
    |       ----          ^^^^^^^^^ ...because it uses `Self` as a type parameter
    |       |
-   |       this trait cannot be made into an object...
-   = help: only type `SExpr<'x>` implements the trait, consider using it directly instead
+   |       this trait is not dyn compatible...
 
-error[E0038]: the trait `Expr` cannot be made into an object
-  --> $DIR/mentions-Self-in-super-predicates.rs:38:16
+error[E0038]: the trait `Expr` is not dyn compatible
+  --> $DIR/mentions-Self-in-super-predicates.rs:38:20
    |
 LL |     let a: Box<dyn Expr> = Box::new(SExpr::new());
-   |                ^^^^^^^^ `Expr` cannot be made into an object
+   |                    ^^^^ `Expr` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/mentions-Self-in-super-predicates.rs:5:21
    |
 LL | trait Expr: Debug + PartialEq {
    |       ----          ^^^^^^^^^ ...because it uses `Self` as a type parameter
    |       |
-   |       this trait cannot be made into an object...
-   = help: only type `SExpr<'x>` implements the trait, consider using it directly instead
+   |       this trait is not dyn compatible...
 
-error[E0038]: the trait `Expr` cannot be made into an object
-  --> $DIR/mentions-Self-in-super-predicates.rs:40:16
+error[E0038]: the trait `Expr` is not dyn compatible
+  --> $DIR/mentions-Self-in-super-predicates.rs:40:20
    |
 LL |     let b: Box<dyn Expr> = Box::new(SExpr::new());
-   |                ^^^^^^^^ `Expr` cannot be made into an object
+   |                    ^^^^ `Expr` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/mentions-Self-in-super-predicates.rs:5:21
    |
 LL | trait Expr: Debug + PartialEq {
    |       ----          ^^^^^^^^^ ...because it uses `Self` as a type parameter
    |       |
-   |       this trait cannot be made into an object...
-   = help: only type `SExpr<'x>` implements the trait, consider using it directly instead
+   |       this trait is not dyn compatible...
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/dyn-compatibility/mentions-Self.curr.stderr b/tests/ui/dyn-compatibility/mentions-Self.curr.stderr
index 434e41cf218..90db86ffef9 100644
--- a/tests/ui/dyn-compatibility/mentions-Self.curr.stderr
+++ b/tests/ui/dyn-compatibility/mentions-Self.curr.stderr
@@ -1,60 +1,64 @@
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/mentions-Self.rs:22:31
    |
 LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-   |                               ^^^^^^^ `Bar` cannot be made into an object
+   |                               ^^^^^^^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/mentions-Self.rs:11:22
    |
 LL | trait Bar {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn bar(&self, x: &Self);
    |                      ^^^^^ ...because method `bar` references the `Self` type in this parameter
    = help: consider moving `bar` to another trait
 
-error[E0038]: the trait `Baz` cannot be made into an object
+error[E0038]: the trait `Baz` is not dyn compatible
   --> $DIR/mentions-Self.rs:28:31
    |
 LL | fn make_baz<T:Baz>(t: &T) -> &dyn Baz {
-   |                               ^^^^^^^ `Baz` cannot be made into an object
+   |                               ^^^^^^^ `Baz` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/mentions-Self.rs:15:22
    |
 LL | trait Baz {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn baz(&self) -> Self;
    |                      ^^^^ ...because method `baz` references the `Self` type in its return type
    = help: consider moving `baz` to another trait
 
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/mentions-Self.rs:24:5
    |
 LL |     t
-   |     ^ `Bar` cannot be made into an object
+   |     ^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/mentions-Self.rs:11:22
    |
 LL | trait Bar {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn bar(&self, x: &Self);
    |                      ^^^^^ ...because method `bar` references the `Self` type in this parameter
    = help: consider moving `bar` to another trait
    = note: required for the cast from `&T` to `&dyn Bar`
 
-error[E0038]: the trait `Baz` cannot be made into an object
+error[E0038]: the trait `Baz` is not dyn compatible
   --> $DIR/mentions-Self.rs:30:5
    |
 LL |     t
-   |     ^ `Baz` cannot be made into an object
+   |     ^ `Baz` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/mentions-Self.rs:15:22
    |
 LL | trait Baz {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn baz(&self) -> Self;
    |                      ^^^^ ...because method `baz` references the `Self` type in its return type
    = help: consider moving `baz` to another trait
diff --git a/tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr
index dc2d1f87eb7..4a50d3f07e4 100644
--- a/tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr
@@ -1,30 +1,32 @@
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/mentions-Self.rs:24:5
    |
 LL |     t
-   |     ^ `Bar` cannot be made into an object
+   |     ^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/mentions-Self.rs:11:22
    |
 LL | trait Bar {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn bar(&self, x: &Self);
    |                      ^^^^^ ...because method `bar` references the `Self` type in this parameter
    = help: consider moving `bar` to another trait
    = note: required for the cast from `&T` to `&dyn Bar`
 
-error[E0038]: the trait `Baz` cannot be made into an object
+error[E0038]: the trait `Baz` is not dyn compatible
   --> $DIR/mentions-Self.rs:30:5
    |
 LL |     t
-   |     ^ `Baz` cannot be made into an object
+   |     ^ `Baz` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/mentions-Self.rs:15:22
    |
 LL | trait Baz {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn baz(&self) -> Self;
    |                      ^^^^ ...because method `baz` references the `Self` type in its return type
    = help: consider moving `baz` to another trait
diff --git a/tests/ui/dyn-compatibility/missing-assoc-type.rs b/tests/ui/dyn-compatibility/missing-assoc-type.rs
index 21f7fd92e80..135761dd036 100644
--- a/tests/ui/dyn-compatibility/missing-assoc-type.rs
+++ b/tests/ui/dyn-compatibility/missing-assoc-type.rs
@@ -2,6 +2,6 @@ trait Foo {
     type Bar<T>;
 }
 
-fn bar(x: &dyn Foo) {} //~ ERROR the trait `Foo` cannot be made into an object
+fn bar(x: &dyn Foo) {} //~ ERROR the trait `Foo` is not dyn compatible
 
 fn main() {}
diff --git a/tests/ui/dyn-compatibility/missing-assoc-type.stderr b/tests/ui/dyn-compatibility/missing-assoc-type.stderr
index 184201dd1ce..3f550494b33 100644
--- a/tests/ui/dyn-compatibility/missing-assoc-type.stderr
+++ b/tests/ui/dyn-compatibility/missing-assoc-type.stderr
@@ -1,14 +1,15 @@
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/missing-assoc-type.rs:5:16
    |
 LL | fn bar(x: &dyn Foo) {}
-   |                ^^^ `Foo` cannot be made into an object
+   |                ^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/missing-assoc-type.rs:2:10
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     type Bar<T>;
    |          ^^^ ...because it contains the generic associated type `Bar`
    = help: consider moving `Bar` to another trait
diff --git a/tests/ui/dyn-compatibility/no-static.curr.stderr b/tests/ui/dyn-compatibility/no-static.curr.stderr
index 584db779855..867c485053d 100644
--- a/tests/ui/dyn-compatibility/no-static.curr.stderr
+++ b/tests/ui/dyn-compatibility/no-static.curr.stderr
@@ -1,17 +1,18 @@
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/no-static.rs:12:22
    |
 LL | fn diverges() -> Box<dyn Foo> {
-   |                      ^^^^^^^ `Foo` cannot be made into an object
+   |                      ^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/no-static.rs:9:8
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn foo() {}
    |        ^^^ ...because associated function `foo` has no `self` parameter
-   = help: only type `Bar` implements the trait, consider using it directly instead
+   = help: only type `Bar` implements `Foo`; consider using it directly instead.
 help: consider turning `foo` into a method by giving it a `&self` argument
    |
 LL |     fn foo(&self) {}
@@ -21,20 +22,21 @@ help: alternatively, consider constraining `foo` so it does not apply to trait o
 LL |     fn foo() where Self: Sized {}
    |              +++++++++++++++++
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/no-static.rs:22:12
    |
 LL |     let b: Box<dyn Foo> = Box::new(Bar);
-   |            ^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |            ^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/no-static.rs:9:8
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn foo() {}
    |        ^^^ ...because associated function `foo` has no `self` parameter
-   = help: only type `Bar` implements the trait, consider using it directly instead
+   = help: only type `Bar` implements `Foo`; consider using it directly instead.
 help: consider turning `foo` into a method by giving it a `&self` argument
    |
 LL |     fn foo(&self) {}
@@ -44,20 +46,21 @@ help: alternatively, consider constraining `foo` so it does not apply to trait o
 LL |     fn foo() where Self: Sized {}
    |              +++++++++++++++++
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/no-static.rs:22:27
    |
 LL |     let b: Box<dyn Foo> = Box::new(Bar);
-   |                           ^^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |                           ^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/no-static.rs:9:8
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn foo() {}
    |        ^^^ ...because associated function `foo` has no `self` parameter
-   = help: only type `Bar` implements the trait, consider using it directly instead
+   = help: only type `Bar` implements `Foo`; consider using it directly instead.
    = note: required for the cast from `Box<Bar>` to `Box<dyn Foo>`
 help: consider turning `foo` into a method by giving it a `&self` argument
    |
diff --git a/tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr
index f2deb3b8d84..65608a9cca7 100644
--- a/tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr
@@ -1,17 +1,18 @@
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/no-static.rs:22:27
    |
 LL |     let b: Box<dyn Foo> = Box::new(Bar);
-   |                           ^^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |                           ^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/no-static.rs:9:8
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn foo() {}
    |        ^^^ ...because associated function `foo` has no `self` parameter
-   = help: only type `Bar` implements the trait, consider using it directly instead
+   = help: only type `Bar` implements `Foo`; consider using it directly instead.
    = note: required for the cast from `Box<Bar>` to `Box<dyn Foo>`
 help: consider turning `foo` into a method by giving it a `&self` argument
    |
diff --git a/tests/ui/dyn-compatibility/sized-2.curr.stderr b/tests/ui/dyn-compatibility/sized-2.curr.stderr
index 1017fde53d3..c8fd1056237 100644
--- a/tests/ui/dyn-compatibility/sized-2.curr.stderr
+++ b/tests/ui/dyn-compatibility/sized-2.curr.stderr
@@ -1,28 +1,30 @@
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/sized-2.rs:14:31
    |
 LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-   |                               ^^^^^^^ `Bar` cannot be made into an object
+   |                               ^^^^^^^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/sized-2.rs:9:18
    |
 LL | trait Bar
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     where Self : Sized
    |                  ^^^^^ ...because it requires `Self: Sized`
 
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/sized-2.rs:16:5
    |
 LL |     t
-   |     ^ `Bar` cannot be made into an object
+   |     ^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/sized-2.rs:9:18
    |
 LL | trait Bar
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     where Self : Sized
    |                  ^^^^^ ...because it requires `Self: Sized`
    = note: required for the cast from `&T` to `&dyn Bar`
diff --git a/tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr
index 534cf0f1b03..477dacdf5a1 100644
--- a/tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr
@@ -1,14 +1,15 @@
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/sized-2.rs:16:5
    |
 LL |     t
-   |     ^ `Bar` cannot be made into an object
+   |     ^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/sized-2.rs:9:18
    |
 LL | trait Bar
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     where Self : Sized
    |                  ^^^^^ ...because it requires `Self: Sized`
    = note: required for the cast from `&T` to `&dyn Bar`
diff --git a/tests/ui/dyn-compatibility/sized.curr.stderr b/tests/ui/dyn-compatibility/sized.curr.stderr
index 613833aad12..d86ea9197b9 100644
--- a/tests/ui/dyn-compatibility/sized.curr.stderr
+++ b/tests/ui/dyn-compatibility/sized.curr.stderr
@@ -1,30 +1,32 @@
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/sized.rs:12:32
    |
 LL | fn make_bar<T: Bar>(t: &T) -> &dyn Bar {
-   |                                ^^^^^^^ `Bar` cannot be made into an object
+   |                                ^^^^^^^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/sized.rs:8:12
    |
 LL | trait Bar: Sized {
    |       ---  ^^^^^ ...because it requires `Self: Sized`
    |       |
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
 
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/sized.rs:14:5
    |
 LL |     t
-   |     ^ `Bar` cannot be made into an object
+   |     ^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/sized.rs:8:12
    |
 LL | trait Bar: Sized {
    |       ---  ^^^^^ ...because it requires `Self: Sized`
    |       |
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
    = note: required for the cast from `&T` to `&dyn Bar`
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr
index cf847bc1577..b763173594b 100644
--- a/tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr
@@ -1,16 +1,17 @@
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/sized.rs:14:5
    |
 LL |     t
-   |     ^ `Bar` cannot be made into an object
+   |     ^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/sized.rs:8:12
    |
 LL | trait Bar: Sized {
    |       ---  ^^^^^ ...because it requires `Self: Sized`
    |       |
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
    = note: required for the cast from `&T` to `&dyn Bar`
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/dyn-compatibility/supertrait-mentions-GAT.rs b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.rs
index 14e00d2ef32..9e5c1bfe416 100644
--- a/tests/ui/dyn-compatibility/supertrait-mentions-GAT.rs
+++ b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.rs
@@ -9,7 +9,7 @@ trait GatTrait {
 trait SuperTrait<T>: for<'a> GatTrait<Gat<'a> = T> {
     fn c(&self) -> dyn SuperTrait<T>;
     //~^ ERROR associated item referring to unboxed trait object for its own trait
-    //~| ERROR the trait `SuperTrait` cannot be made into an object
+    //~| ERROR the trait `SuperTrait` is not dyn compatible
 }
 
 fn main() {}
diff --git a/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr
index ac5a5b28d94..f5dea256469 100644
--- a/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr
+++ b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr
@@ -20,20 +20,21 @@ help: you might have meant to use `Self` to refer to the implementing type
 LL |     fn c(&self) -> Self;
    |                    ~~~~
 
-error[E0038]: the trait `SuperTrait` cannot be made into an object
+error[E0038]: the trait `SuperTrait` is not dyn compatible
   --> $DIR/supertrait-mentions-GAT.rs:10:20
    |
 LL |     fn c(&self) -> dyn SuperTrait<T>;
-   |                    ^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
+   |                    ^^^^^^^^^^^^^^^^^ `SuperTrait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/supertrait-mentions-GAT.rs:4:10
    |
 LL |     type Gat<'a>
    |          ^^^ ...because it contains the generic associated type `Gat`
 ...
 LL | trait SuperTrait<T>: for<'a> GatTrait<Gat<'a> = T> {
-   |       ---------- this trait cannot be made into an object...
+   |       ---------- this trait is not dyn compatible...
    = help: consider moving `Gat` to another trait
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/dyn-compatibility/supertrait-mentions-Self.stderr b/tests/ui/dyn-compatibility/supertrait-mentions-Self.stderr
index 6474b115c46..f9ef0c9b2e0 100644
--- a/tests/ui/dyn-compatibility/supertrait-mentions-Self.stderr
+++ b/tests/ui/dyn-compatibility/supertrait-mentions-Self.stderr
@@ -18,19 +18,20 @@ help: consider relaxing the implicit `Sized` restriction
 LL | trait Bar<T: ?Sized> {
    |            ++++++++
 
-error[E0038]: the trait `Baz` cannot be made into an object
-  --> $DIR/supertrait-mentions-Self.rs:16:31
+error[E0038]: the trait `Baz` is not dyn compatible
+  --> $DIR/supertrait-mentions-Self.rs:16:35
    |
 LL | fn make_baz<T:Baz>(t: &T) -> &dyn Baz {
-   |                               ^^^^^^^ `Baz` cannot be made into an object
+   |                                   ^^^ `Baz` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/supertrait-mentions-Self.rs:8:13
    |
 LL | trait Baz : Bar<Self> {
    |       ---   ^^^^^^^^^ ...because it uses `Self` as a type parameter
    |       |
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
 help: consider using an opaque type instead
    |
 LL | fn make_baz<T:Baz>(t: &T) -> &impl Baz {
diff --git a/tests/ui/dyn-compatibility/taint-const-eval.curr.stderr b/tests/ui/dyn-compatibility/taint-const-eval.curr.stderr
index ef0abc16342..8442314835e 100644
--- a/tests/ui/dyn-compatibility/taint-const-eval.curr.stderr
+++ b/tests/ui/dyn-compatibility/taint-const-eval.curr.stderr
@@ -1,14 +1,15 @@
-error[E0038]: the trait `Qux` cannot be made into an object
+error[E0038]: the trait `Qux` is not dyn compatible
   --> $DIR/taint-const-eval.rs:11:15
    |
 LL | static FOO: &(dyn Qux + Sync) = "desc";
-   |               ^^^^^^^^^^^^^^ `Qux` cannot be made into an object
+   |               ^^^^^^^^^^^^^^ `Qux` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/taint-const-eval.rs:8:8
    |
 LL | trait Qux {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn bar();
    |        ^^^ ...because associated function `bar` has no `self` parameter
 help: consider turning `bar` into a method by giving it a `&self` argument
@@ -20,17 +21,18 @@ help: alternatively, consider constraining `bar` so it does not apply to trait o
 LL |     fn bar() where Self: Sized;
    |              +++++++++++++++++
 
-error[E0038]: the trait `Qux` cannot be made into an object
+error[E0038]: the trait `Qux` is not dyn compatible
   --> $DIR/taint-const-eval.rs:11:33
    |
 LL | static FOO: &(dyn Qux + Sync) = "desc";
-   |                                 ^^^^^^ `Qux` cannot be made into an object
+   |                                 ^^^^^^ `Qux` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/taint-const-eval.rs:8:8
    |
 LL | trait Qux {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn bar();
    |        ^^^ ...because associated function `bar` has no `self` parameter
    = note: required for the cast from `&'static str` to `&'static (dyn Qux + Sync + 'static)`
@@ -43,17 +45,18 @@ help: alternatively, consider constraining `bar` so it does not apply to trait o
 LL |     fn bar() where Self: Sized;
    |              +++++++++++++++++
 
-error[E0038]: the trait `Qux` cannot be made into an object
+error[E0038]: the trait `Qux` is not dyn compatible
   --> $DIR/taint-const-eval.rs:11:15
    |
 LL | static FOO: &(dyn Qux + Sync) = "desc";
-   |               ^^^^^^^^^^^^^^ `Qux` cannot be made into an object
+   |               ^^^^^^^^^^^^^^ `Qux` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/taint-const-eval.rs:8:8
    |
 LL | trait Qux {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn bar();
    |        ^^^ ...because associated function `bar` has no `self` parameter
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
diff --git a/tests/ui/dyn-compatibility/taint-const-eval.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/taint-const-eval.dyn_compatible_for_dispatch.stderr
index 14940365d23..1c51df8501f 100644
--- a/tests/ui/dyn-compatibility/taint-const-eval.dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/dyn-compatibility/taint-const-eval.dyn_compatible_for_dispatch.stderr
@@ -1,14 +1,15 @@
-error[E0038]: the trait `Qux` cannot be made into an object
+error[E0038]: the trait `Qux` is not dyn compatible
   --> $DIR/taint-const-eval.rs:11:33
    |
 LL | static FOO: &(dyn Qux + Sync) = "desc";
-   |                                 ^^^^^^ `Qux` cannot be made into an object
+   |                                 ^^^^^^ `Qux` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/taint-const-eval.rs:8:8
    |
 LL | trait Qux {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn bar();
    |        ^^^ ...because associated function `bar` has no `self` parameter
    = note: required for the cast from `&'static str` to `&'static (dyn Qux + Sync + 'static)`
diff --git a/tests/ui/dyn-compatibility/taint-const-eval.rs b/tests/ui/dyn-compatibility/taint-const-eval.rs
index 9825ec0ca1c..2feae58080b 100644
--- a/tests/ui/dyn-compatibility/taint-const-eval.rs
+++ b/tests/ui/dyn-compatibility/taint-const-eval.rs
@@ -9,8 +9,8 @@ trait Qux {
 }
 
 static FOO: &(dyn Qux + Sync) = "desc";
-//~^ the trait `Qux` cannot be made into an object
-//[curr]~| the trait `Qux` cannot be made into an object
-//[curr]~| the trait `Qux` cannot be made into an object
+//~^ the trait `Qux` is not dyn compatible
+//[curr]~| the trait `Qux` is not dyn compatible
+//[curr]~| the trait `Qux` is not dyn compatible
 
 fn main() {}
diff --git a/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.rs b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.rs
index 5c71bd7769c..ec32bec7785 100644
--- a/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.rs
+++ b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.rs
@@ -17,13 +17,13 @@ pub trait Fetcher: Send + Sync {
 }
 
 fn fetcher() -> Box<dyn Fetcher> {
-    //~^ ERROR the trait `Fetcher` cannot be made into an object
+    //~^ ERROR the trait `Fetcher` is not dyn compatible
     todo!()
 }
 
 pub fn foo() {
     let fetcher = fetcher();
-    //~^ ERROR the trait `Fetcher` cannot be made into an object
+    //~^ ERROR the trait `Fetcher` is not dyn compatible
     let _ = fetcher.get();
-    //~^ ERROR the trait `Fetcher` cannot be made into an object
+    //~^ ERROR the trait `Fetcher` is not dyn compatible
 }
diff --git a/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr
index 8d62ac9d923..45a924008c7 100644
--- a/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr
+++ b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr
@@ -1,51 +1,54 @@
-error[E0038]: the trait `Fetcher` cannot be made into an object
+error[E0038]: the trait `Fetcher` is not dyn compatible
   --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:19:21
    |
 LL |     fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
    |                      ------------- help: consider changing method `get`'s `self` parameter to be `&self`: `&Self`
 ...
 LL | fn fetcher() -> Box<dyn Fetcher> {
-   |                     ^^^^^^^^^^^ `Fetcher` cannot be made into an object
+   |                     ^^^^^^^^^^^ `Fetcher` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:11:22
    |
 LL | pub trait Fetcher: Send + Sync {
-   |           ------- this trait cannot be made into an object...
+   |           ------- this trait is not dyn compatible...
 LL |     fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
    |                      ^^^^^^^^^^^^^ ...because method `get`'s `self` parameter cannot be dispatched on
 
-error[E0038]: the trait `Fetcher` cannot be made into an object
+error[E0038]: the trait `Fetcher` is not dyn compatible
   --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:25:19
    |
 LL |     fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
    |                      ------------- help: consider changing method `get`'s `self` parameter to be `&self`: `&Self`
 ...
 LL |     let fetcher = fetcher();
-   |                   ^^^^^^^^^ `Fetcher` cannot be made into an object
+   |                   ^^^^^^^^^ `Fetcher` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:11:22
    |
 LL | pub trait Fetcher: Send + Sync {
-   |           ------- this trait cannot be made into an object...
+   |           ------- this trait is not dyn compatible...
 LL |     fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
    |                      ^^^^^^^^^^^^^ ...because method `get`'s `self` parameter cannot be dispatched on
 
-error[E0038]: the trait `Fetcher` cannot be made into an object
+error[E0038]: the trait `Fetcher` is not dyn compatible
   --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:27:13
    |
 LL |     fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
    |                      ------------- help: consider changing method `get`'s `self` parameter to be `&self`: `&Self`
 ...
 LL |     let _ = fetcher.get();
-   |             ^^^^^^^^^^^^^ `Fetcher` cannot be made into an object
+   |             ^^^^^^^^^^^^^ `Fetcher` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:11:22
    |
 LL | pub trait Fetcher: Send + Sync {
-   |           ------- this trait cannot be made into an object...
+   |           ------- this trait is not dyn compatible...
 LL |     fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
    |                      ^^^^^^^^^^^^^ ...because method `get`'s `self` parameter cannot be dispatched on
 
diff --git a/tests/ui/error-codes/E0038.stderr b/tests/ui/error-codes/E0038.stderr
index 54b489c655f..59e9f504d17 100644
--- a/tests/ui/error-codes/E0038.stderr
+++ b/tests/ui/error-codes/E0038.stderr
@@ -1,29 +1,31 @@
-error[E0038]: the trait `Trait` cannot be made into an object
+error[E0038]: the trait `Trait` is not dyn compatible
   --> $DIR/E0038.rs:5:20
    |
 LL | fn call_foo(x: Box<dyn Trait>) {
-   |                    ^^^^^^^^^ `Trait` cannot be made into an object
+   |                    ^^^^^^^^^ `Trait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/E0038.rs:2:22
    |
 LL | trait Trait {
-   |       ----- this trait cannot be made into an object...
+   |       ----- this trait is not dyn compatible...
 LL |     fn foo(&self) -> Self;
    |                      ^^^^ ...because method `foo` references the `Self` type in its return type
    = help: consider moving `foo` to another trait
 
-error[E0038]: the trait `Trait` cannot be made into an object
+error[E0038]: the trait `Trait` is not dyn compatible
   --> $DIR/E0038.rs:7:13
    |
 LL |     let y = x.foo();
-   |             ^^^^^^^ `Trait` cannot be made into an object
+   |             ^^^^^^^ `Trait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/E0038.rs:2:22
    |
 LL | trait Trait {
-   |       ----- this trait cannot be made into an object...
+   |       ----- this trait is not dyn compatible...
 LL |     fn foo(&self) -> Self;
    |                      ^^^^ ...because method `foo` references the `Self` type in its return type
    = help: consider moving `foo` to another trait
diff --git a/tests/ui/error-codes/E0132.rs b/tests/ui/error-codes/E0132.rs
deleted file mode 100644
index fb5e5d7b95a..00000000000
--- a/tests/ui/error-codes/E0132.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-#![feature(start)]
-
-#[start]
-fn f< T >() {} //~ ERROR E0132
-
-fn main() {
-}
diff --git a/tests/ui/error-codes/E0132.stderr b/tests/ui/error-codes/E0132.stderr
deleted file mode 100644
index b1990afa3ae..00000000000
--- a/tests/ui/error-codes/E0132.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0132]: `#[start]` function is not allowed to have type parameters
-  --> $DIR/E0132.rs:4:5
-   |
-LL | fn f< T >() {}
-   |     ^^^^^ `#[start]` function cannot have type parameters
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0132`.
diff --git a/tests/ui/error-codes/E0138.rs b/tests/ui/error-codes/E0138.rs
deleted file mode 100644
index 6f3c36282e8..00000000000
--- a/tests/ui/error-codes/E0138.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-#![feature(start)]
-
-#[start]
-fn foo(argc: isize, argv: *const *const u8) -> isize { 0 }
-
-#[start]
-fn f(argc: isize, argv: *const *const u8) -> isize { 0 }
-//~^ ERROR E0138
diff --git a/tests/ui/error-codes/E0138.stderr b/tests/ui/error-codes/E0138.stderr
deleted file mode 100644
index 04877ab4082..00000000000
--- a/tests/ui/error-codes/E0138.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0138]: multiple `start` functions
-  --> $DIR/E0138.rs:7:1
-   |
-LL | fn foo(argc: isize, argv: *const *const u8) -> isize { 0 }
-   | ---------------------------------------------------- previous `#[start]` function here
-...
-LL | fn f(argc: isize, argv: *const *const u8) -> isize { 0 }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ multiple `start` functions
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0138`.
diff --git a/tests/ui/error-codes/E0225.stderr b/tests/ui/error-codes/E0225.stderr
index a4b33a0b7b4..e6781282c8f 100644
--- a/tests/ui/error-codes/E0225.stderr
+++ b/tests/ui/error-codes/E0225.stderr
@@ -20,8 +20,8 @@ LL | trait Foo = std::io::Read + std::io::Write;
 LL |     let _: Box<dyn Foo>;
    |                    ^^^
    |                    |
-   |                    trait alias used in trait object type (additional use)
-   |                    trait alias used in trait object type (first use)
+   |                    first non-auto trait comes from this alias
+   |                    second non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: std::io::Read + std::io::Write {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
diff --git a/tests/ui/error-codes/E0451.stderr b/tests/ui/error-codes/E0451.stderr
index 419cf117efe..2cd30095c80 100644
--- a/tests/ui/error-codes/E0451.stderr
+++ b/tests/ui/error-codes/E0451.stderr
@@ -8,7 +8,7 @@ error[E0451]: field `b` of struct `Foo` is private
   --> $DIR/E0451.rs:18:29
    |
 LL |     let f = bar::Foo{ a: 0, b: 0 };
-   |                             ^^^^ private field
+   |                             ^ private field
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/error-codes/E0647.rs b/tests/ui/error-codes/E0647.rs
deleted file mode 100644
index fc085511cbc..00000000000
--- a/tests/ui/error-codes/E0647.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-#![no_std]
-#![feature(start)]
-
-extern crate std;
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize where (): Copy { //~ ERROR [E0647]
-    0
-}
diff --git a/tests/ui/error-codes/E0647.stderr b/tests/ui/error-codes/E0647.stderr
deleted file mode 100644
index 4b444e5a397..00000000000
--- a/tests/ui/error-codes/E0647.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0647]: `#[start]` function is not allowed to have a `where` clause
-  --> $DIR/E0647.rs:7:50
-   |
-LL | fn start(_: isize, _: *const *const u8) -> isize where (): Copy {
-   |                                                  ^^^^^^^^^^^^^^ `#[start]` function cannot have a `where` clause
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0647`.
diff --git a/tests/ui/expr/if/if-let.stderr b/tests/ui/expr/if/if-let.stderr
index c4bba3cb1a8..792504a9772 100644
--- a/tests/ui/expr/if/if-let.stderr
+++ b/tests/ui/expr/if/if-let.stderr
@@ -2,7 +2,7 @@ warning: irrefutable `if let` pattern
   --> $DIR/if-let.rs:6:16
    |
 LL |               if let $p = $e $b
-   |                  ^^^
+   |                  ^^^^^^^^^^^
 ...
 LL | /     foo!(a, 1, {
 LL | |         println!("irrefutable pattern");
diff --git a/tests/ui/extern/extern-prelude-core.rs b/tests/ui/extern/extern-prelude-core.rs
index ced1e5c3915..5108c02517c 100644
--- a/tests/ui/extern/extern-prelude-core.rs
+++ b/tests/ui/extern/extern-prelude-core.rs
@@ -1,5 +1,5 @@
 //@ run-pass
-#![feature(lang_items, start)]
+#![feature(lang_items)]
 #![no_std]
 
 extern crate std as other;
@@ -11,8 +11,6 @@ mod foo {
     }
 }
 
-#[start]
-fn start(_argc: isize, _argv: *const *const u8) -> isize {
+fn main() {
     foo::test();
-    0
 }
diff --git a/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs
index d9ff45f57ec..278a5451e84 100644
--- a/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs
+++ b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs
@@ -5,10 +5,10 @@ trait Foo {
 }
 
 async fn takes_dyn_trait(x: &dyn Foo) {
-    //~^ ERROR the trait `Foo` cannot be made into an object
+    //~^ ERROR the trait `Foo` is not dyn compatible
     x.bar().await;
-    //~^ ERROR the trait `Foo` cannot be made into an object
-    //~| ERROR the trait `Foo` cannot be made into an object
+    //~^ ERROR the trait `Foo` is not dyn compatible
+    //~| ERROR the trait `Foo` is not dyn compatible
 }
 
 fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr
index f78fc422410..b4de6b66469 100644
--- a/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr
+++ b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr
@@ -1,44 +1,47 @@
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:7:30
    |
 LL | async fn takes_dyn_trait(x: &dyn Foo) {
-   |                              ^^^^^^^ `Foo` cannot be made into an object
+   |                              ^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     async fn bar(&self);
    |              ^^^ ...because method `bar` is `async`
    = help: consider moving `bar` to another trait
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:9:7
    |
 LL |     x.bar().await;
-   |       ^^^ `Foo` cannot be made into an object
+   |       ^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     async fn bar(&self);
    |              ^^^ ...because method `bar` is `async`
    = help: consider moving `bar` to another trait
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:9:5
    |
 LL |     x.bar().await;
-   |     ^^^^^^^ `Foo` cannot be made into an object
+   |     ^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     async fn bar(&self);
    |              ^^^ ...because method `bar` is `async`
    = help: consider moving `bar` to another trait
diff --git a/tests/ui/feature-gates/feature-gate-default-field-values.stderr b/tests/ui/feature-gates/feature-gate-default-field-values.stderr
index d882c322c8e..104d72a3986 100644
--- a/tests/ui/feature-gates/feature-gate-default-field-values.stderr
+++ b/tests/ui/feature-gates/feature-gate-default-field-values.stderr
@@ -130,7 +130,10 @@ error[E0797]: base expression required after `..`
 LL |     let x = Foo { .. };
    |                     ^
    |
-   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+   |
+LL + #![feature(default_field_values)]
+   |
 help: add a base expression here
    |
 LL |     let x = Foo { ../* expr */ };
@@ -142,7 +145,10 @@ error[E0797]: base expression required after `..`
 LL |     let z = Foo { baz: 1, .. };
    |                             ^
    |
-   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+   |
+LL + #![feature(default_field_values)]
+   |
 help: add a base expression here
    |
 LL |     let z = Foo { baz: 1, ../* expr */ };
@@ -154,7 +160,10 @@ error[E0797]: base expression required after `..`
 LL |     let x = Bar::Foo { .. };
    |                          ^
    |
-   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+   |
+LL + #![feature(default_field_values)]
+   |
 help: add a base expression here
    |
 LL |     let x = Bar::Foo { ../* expr */ };
@@ -166,7 +175,10 @@ error[E0797]: base expression required after `..`
 LL |     let z = Bar::Foo { baz: 1, .. };
    |                                  ^
    |
-   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+   |
+LL + #![feature(default_field_values)]
+   |
 help: add a base expression here
    |
 LL |     let z = Bar::Foo { baz: 1, ../* expr */ };
@@ -178,7 +190,10 @@ error[E0797]: base expression required after `..`
 LL |     let x = Qux::<i32, 4> { .. };
    |                               ^
    |
-   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+   |
+LL + #![feature(default_field_values)]
+   |
 help: add a base expression here
    |
 LL |     let x = Qux::<i32, 4> { ../* expr */ };
@@ -190,7 +205,10 @@ error[E0797]: base expression required after `..`
 LL |     assert!(matches!(Qux::<i32, 4> { bar: S, baz: 42, bat: 2, bay: 4, .. }, x));
    |                                                                         ^
    |
-   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+   |
+LL + #![feature(default_field_values)]
+   |
 help: add a base expression here
    |
 LL |     assert!(matches!(Qux::<i32, 4> { bar: S, baz: 42, bat: 2, bay: 4, ../* expr */ }, x));
@@ -202,7 +220,10 @@ error[E0797]: base expression required after `..`
 LL |     let y = Opt { mandatory: None, .. };
    |                                      ^
    |
-   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+   |
+LL + #![feature(default_field_values)]
+   |
 help: add a base expression here
    |
 LL |     let y = Opt { mandatory: None, ../* expr */ };
@@ -214,7 +235,10 @@ error[E0797]: base expression required after `..`
 LL |     assert!(matches!(Opt { mandatory: None, .. }, z));
    |                                               ^
    |
-   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+   |
+LL + #![feature(default_field_values)]
+   |
 help: add a base expression here
    |
 LL |     assert!(matches!(Opt { mandatory: None, ../* expr */ }, z));
@@ -260,7 +284,10 @@ error[E0797]: base expression required after `..`
 LL |     let y = OptEnum::Variant { mandatory: None, .. };
    |                                                   ^
    |
-   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+   |
+LL + #![feature(default_field_values)]
+   |
 help: add a base expression here
    |
 LL |     let y = OptEnum::Variant { mandatory: None, ../* expr */ };
@@ -272,7 +299,10 @@ error[E0797]: base expression required after `..`
 LL |     assert!(matches!(OptEnum::Variant { mandatory: None, .. }, z));
    |                                                            ^
    |
-   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+   |
+LL + #![feature(default_field_values)]
+   |
 help: add a base expression here
    |
 LL |     assert!(matches!(OptEnum::Variant { mandatory: None, ../* expr */ }, z));
diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs
index 3c9e903d4ba..37eabbf1602 100644
--- a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs
+++ b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs
@@ -30,6 +30,6 @@ impl Trait for i32 {
 
 fn main() {
     Ptr(Box::new(4)) as Ptr<dyn Trait>;
-    //~^ ERROR the trait `Trait` cannot be made into an object
-    //~^^ ERROR the trait `Trait` cannot be made into an object
+    //~^ ERROR the trait `Trait` is not dyn compatible
+    //~^^ ERROR the trait `Trait` is not dyn compatible
 }
diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr
index 28caaf8356f..f8fc086c441 100644
--- a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr
+++ b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr
@@ -1,38 +1,40 @@
-error[E0038]: the trait `Trait` cannot be made into an object
+error[E0038]: the trait `Trait` is not dyn compatible
   --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:32:25
    |
 LL |     fn ptr(self: Ptr<Self>);
    |                  --------- help: consider changing method `ptr`'s `self` parameter to be `&self`: `&Self`
 ...
 LL |     Ptr(Box::new(4)) as Ptr<dyn Trait>;
-   |                         ^^^^^^^^^^^^^^ `Trait` cannot be made into an object
+   |                         ^^^^^^^^^^^^^^ `Trait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:18
    |
 LL | trait Trait {
-   |       ----- this trait cannot be made into an object...
+   |       ----- this trait is not dyn compatible...
 LL |     fn ptr(self: Ptr<Self>);
    |                  ^^^^^^^^^ ...because method `ptr`'s `self` parameter cannot be dispatched on
-   = help: only type `i32` implements the trait, consider using it directly instead
+   = help: only type `i32` implements `Trait`; consider using it directly instead.
 
-error[E0038]: the trait `Trait` cannot be made into an object
+error[E0038]: the trait `Trait` is not dyn compatible
   --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:32:5
    |
 LL |     fn ptr(self: Ptr<Self>);
    |                  --------- help: consider changing method `ptr`'s `self` parameter to be `&self`: `&Self`
 ...
 LL |     Ptr(Box::new(4)) as Ptr<dyn Trait>;
-   |     ^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
+   |     ^^^^^^^^^^^^^^^^ `Trait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:18
    |
 LL | trait Trait {
-   |       ----- this trait cannot be made into an object...
+   |       ----- this trait is not dyn compatible...
 LL |     fn ptr(self: Ptr<Self>);
    |                  ^^^^^^^^^ ...because method `ptr`'s `self` parameter cannot be dispatched on
-   = help: only type `i32` implements the trait, consider using it directly instead
+   = help: only type `i32` implements `Trait`; consider using it directly instead.
    = note: required for the cast from `Ptr<{integer}>` to `Ptr<dyn Trait>`
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr b/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr
index ed021c154a5..10540f0219d 100644
--- a/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr
@@ -1,28 +1,30 @@
-error[E0038]: the trait `DynIncompatible1` cannot be made into an object
+error[E0038]: the trait `DynIncompatible1` is not dyn compatible
   --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:18:40
    |
 LL | fn takes_dyn_incompatible_ref<T>(obj: &dyn DynIncompatible1) {
-   |                                        ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible1` cannot be made into an object
+   |                                        ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible1` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:4:25
    |
 LL | trait DynIncompatible1: Sized {}
    |       ----------------  ^^^^^ ...because it requires `Self: Sized`
    |       |
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
 
-error[E0038]: the trait `DynIncompatible2` cannot be made into an object
+error[E0038]: the trait `DynIncompatible2` is not dyn compatible
   --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:22:46
    |
 LL | fn return_dyn_incompatible_ref() -> &'static dyn DynIncompatible2 {
-   |                                              ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible2` cannot be made into an object
+   |                                              ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible2` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:7:8
    |
 LL | trait DynIncompatible2 {
-   |       ---------------- this trait cannot be made into an object...
+   |       ---------------- this trait is not dyn compatible...
 LL |     fn static_fn() {}
    |        ^^^^^^^^^ ...because associated function `static_fn` has no `self` parameter
 help: consider turning `static_fn` into a method by giving it a `&self` argument
@@ -34,49 +36,52 @@ help: alternatively, consider constraining `static_fn` so it does not apply to t
 LL |     fn static_fn() where Self: Sized {}
    |                    +++++++++++++++++
 
-error[E0038]: the trait `DynIncompatible3` cannot be made into an object
+error[E0038]: the trait `DynIncompatible3` is not dyn compatible
   --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:27:40
    |
 LL | fn takes_dyn_incompatible_box(obj: Box<dyn DynIncompatible3>) {
-   |                                        ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible3` cannot be made into an object
+   |                                        ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible3` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:11:8
    |
 LL | trait DynIncompatible3 {
-   |       ---------------- this trait cannot be made into an object...
+   |       ---------------- this trait is not dyn compatible...
 LL |     fn foo<T>(&self);
    |        ^^^ ...because method `foo` has generic type parameters
    = help: consider moving `foo` to another trait
 
-error[E0038]: the trait `DynIncompatible4` cannot be made into an object
+error[E0038]: the trait `DynIncompatible4` is not dyn compatible
   --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:31:48
    |
 LL | fn return_dyn_incompatible_rc() -> std::rc::Rc<dyn DynIncompatible4> {
-   |                                                ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible4` cannot be made into an object
+   |                                                ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible4` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:15:22
    |
 LL | trait DynIncompatible4 {
-   |       ---------------- this trait cannot be made into an object...
+   |       ---------------- this trait is not dyn compatible...
 LL |     fn foo(&self, s: &Self);
    |                      ^^^^^ ...because method `foo` references the `Self` type in this parameter
    = help: consider moving `foo` to another trait
 
-error[E0038]: the trait `DynIncompatible1` cannot be made into an object
+error[E0038]: the trait `DynIncompatible1` is not dyn compatible
   --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:38:16
    |
 LL | impl Trait for dyn DynIncompatible1 {}
-   |                ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible1` cannot be made into an object
+   |                ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible1` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:4:25
    |
 LL | trait DynIncompatible1: Sized {}
    |       ----------------  ^^^^^ ...because it requires `Self: Sized`
    |       |
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/feature-gates/feature-gate-start.rs b/tests/ui/feature-gates/feature-gate-start.rs
deleted file mode 100644
index e617f1c4759..00000000000
--- a/tests/ui/feature-gates/feature-gate-start.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-#[start]
-fn foo(_: isize, _: *const *const u8) -> isize { 0 }
-//~^ ERROR `#[start]` functions are experimental
diff --git a/tests/ui/feature-gates/feature-gate-start.stderr b/tests/ui/feature-gates/feature-gate-start.stderr
deleted file mode 100644
index b1859c43718..00000000000
--- a/tests/ui/feature-gates/feature-gate-start.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0658]: `#[start]` functions are experimental and their signature may change over time
-  --> $DIR/feature-gate-start.rs:2:1
-   |
-LL | fn foo(_: isize, _: *const *const u8) -> isize { 0 }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #29633 <https://github.com/rust-lang/rust/issues/29633> for more information
-   = help: add `#![feature(start)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
index afffb3b1443..02a56c7e6aa 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
@@ -14,8 +14,6 @@
 #![rustc_main] //~ ERROR: the `#[rustc_main]` attribute is used internally to specify
 //~^ ERROR: `rustc_main` attribute cannot be used at crate level
 //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-#![start]
-//~^ ERROR: `start` attribute cannot be used at crate level
 #![repr()]
 //~^ ERROR: `repr` attribute cannot be used at crate level
 #![path = "3800"]
@@ -38,7 +36,6 @@ mod inline {
     //~| NOTE the inner attribute doesn't annotate this module
     //~| NOTE the inner attribute doesn't annotate this module
     //~| NOTE the inner attribute doesn't annotate this module
-    //~| NOTE the inner attribute doesn't annotate this module
 
     mod inner { #![inline] }
     //~^ ERROR attribute should be applied to function or closure
@@ -123,24 +120,6 @@ mod export_name {
     }
 }
 
-#[start]
-//~^ ERROR: `start` attribute can only be used on functions
-mod start {
-    mod inner { #![start] }
-    //~^ ERROR: `start` attribute can only be used on functions
-
-    // for `fn f()` case, see feature-gate-start.rs
-
-    #[start] struct S;
-    //~^ ERROR: `start` attribute can only be used on functions
-
-    #[start] type T = S;
-    //~^ ERROR: `start` attribute can only be used on functions
-
-    #[start] impl S { }
-    //~^ ERROR: `start` attribute can only be used on functions
-}
-
 #[repr(C)]
 //~^ ERROR: attribute should be applied to a struct, enum, or union
 mod repr {
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
index db8c5295a2d..648bafe6460 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
@@ -8,7 +8,7 @@ LL | #![rustc_main]
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: valid forms for the attribute are `#[inline]` and `#[inline(always|never)]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:47:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:44:5
    |
 LL |     #[inline = "2100"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^
@@ -17,38 +17,8 @@ LL |     #[inline = "2100"] fn f() { }
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
    = note: `#[deny(ill_formed_attribute_input)]` on by default
 
-error: `start` attribute can only be used on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:126:1
-   |
-LL | #[start]
-   | ^^^^^^^^
-
-error: `start` attribute can only be used on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:129:17
-   |
-LL |     mod inner { #![start] }
-   |                 ^^^^^^^^^
-
-error: `start` attribute can only be used on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:134:5
-   |
-LL |     #[start] struct S;
-   |     ^^^^^^^^
-
-error: `start` attribute can only be used on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:137:5
-   |
-LL |     #[start] type T = S;
-   |     ^^^^^^^^
-
-error: `start` attribute can only be used on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:140:5
-   |
-LL |     #[start] impl S { }
-   |     ^^^^^^^^
-
 error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:32:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:30:1
    |
 LL |   #[inline]
    |   ^^^^^^^^^
@@ -59,7 +29,7 @@ LL | | }
    | |_- not a function or closure
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:66:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:63:1
    |
 LL |   #[no_link]
    |   ^^^^^^^^^^
@@ -73,7 +43,7 @@ LL | | }
    | |_- not an `extern crate` item
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:92:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:89:1
    |
 LL |   #[export_name = "2200"]
    |   ^^^^^^^^^^^^^^^^^^^^^^^
@@ -87,7 +57,7 @@ LL | | }
    | |_- not a free function, impl method or static
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:144:8
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:123:8
    |
 LL |   #[repr(C)]
    |          ^
@@ -100,7 +70,7 @@ LL | | }
    | |_- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:168:8
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:147:8
    |
 LL |   #[repr(Rust)]
    |          ^^^^
@@ -113,19 +83,19 @@ LL | | }
    | |_- not a struct, enum, or union
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:26:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:24:1
    |
 LL | #![no_link]
    | ^^^^^^^^^^^ not an `extern crate` item
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:26:1
    |
 LL | #![export_name = "2200"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^ not a free function, impl method or static
 
 error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:30:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:1
    |
 LL | #![inline]
    | ^^^^^^^^^^ not a function or closure
@@ -160,23 +130,8 @@ LL - #![rustc_main]
 LL + #[rustc_main]
    |
 
-error: `start` attribute cannot be used at crate level
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:17:1
-   |
-LL | #![start]
-   | ^^^^^^^^^
-...
-LL | mod inline {
-   |     ------ the inner attribute doesn't annotate this module
-   |
-help: perhaps you meant to use an outer attribute
-   |
-LL - #![start]
-LL + #[start]
-   |
-
 error: `repr` attribute cannot be used at crate level
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:17:1
    |
 LL | #![repr()]
    | ^^^^^^^^^^
@@ -191,7 +146,7 @@ LL + #[repr()]
    |
 
 error: `path` attribute cannot be used at crate level
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:21:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1
    |
 LL | #![path = "3800"]
    | ^^^^^^^^^^^^^^^^^
@@ -206,7 +161,7 @@ LL + #[path = "3800"]
    |
 
 error: `automatically_derived` attribute cannot be used at crate level
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:23:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:21:1
    |
 LL | #![automatically_derived]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -221,144 +176,144 @@ LL + #[automatically_derived]
    |
 
 error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:43:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:40:17
    |
 LL |     mod inner { #![inline] }
    |     ------------^^^^^^^^^^-- not a function or closure
 
 error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:53:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:50:5
    |
 LL |     #[inline] struct S;
    |     ^^^^^^^^^ --------- not a function or closure
 
 error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:57:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:54:5
    |
 LL |     #[inline] type T = S;
    |     ^^^^^^^^^ ----------- not a function or closure
 
 error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:61:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:58:5
    |
 LL |     #[inline] impl S { }
    |     ^^^^^^^^^ ---------- not a function or closure
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:71:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:68:17
    |
 LL |     mod inner { #![no_link] }
    |     ------------^^^^^^^^^^^-- not an `extern crate` item
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:75:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:72:5
    |
 LL |     #[no_link] fn f() { }
    |     ^^^^^^^^^^ ---------- not an `extern crate` item
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:79:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:76:5
    |
 LL |     #[no_link] struct S;
    |     ^^^^^^^^^^ --------- not an `extern crate` item
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:83:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:80:5
    |
 LL |     #[no_link]type T = S;
    |     ^^^^^^^^^^----------- not an `extern crate` item
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:87:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:84:5
    |
 LL |     #[no_link] impl S { }
    |     ^^^^^^^^^^ ---------- not an `extern crate` item
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:97:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:94:17
    |
 LL |     mod inner { #![export_name="2200"] }
    |     ------------^^^^^^^^^^^^^^^^^^^^^^-- not a free function, impl method or static
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:103:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:100:5
    |
 LL |     #[export_name = "2200"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:107:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:104:5
    |
 LL |     #[export_name = "2200"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:111:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:108:5
    |
 LL |     #[export_name = "2200"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a free function, impl method or static
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:116:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:113:9
    |
 LL |         #[export_name = "2200"] fn foo();
    |         ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:120:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:117:9
    |
 LL |         #[export_name = "2200"] fn bar() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:148:25
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:127:25
    |
 LL |     mod inner { #![repr(C)] }
    |     --------------------^---- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:152:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:131:12
    |
 LL |     #[repr(C)] fn f() { }
    |            ^   ---------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:158:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:137:12
    |
 LL |     #[repr(C)] type T = S;
    |            ^   ----------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:162:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:141:12
    |
 LL |     #[repr(C)] impl S { }
    |            ^   ---------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:172:25
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:151:25
    |
 LL |     mod inner { #![repr(Rust)] }
    |     --------------------^^^^---- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:176:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:155:12
    |
 LL |     #[repr(Rust)] fn f() { }
    |            ^^^^   ---------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:182:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:161:12
    |
 LL |     #[repr(Rust)] type T = S;
    |            ^^^^   ----------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:186:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:165:12
    |
 LL |     #[repr(Rust)] impl S { }
    |            ^^^^   ---------- not a struct, enum, or union
 
-error: aborting due to 44 previous errors
+error: aborting due to 38 previous errors
 
 Some errors have detailed explanations: E0517, E0518, E0658.
 For more information about an error, try `rustc --explain E0517`.
diff --git a/tests/ui/for-loop-while/for-loop-no-std.rs b/tests/ui/for-loop-while/for-loop-no-std.rs
index 4511146dc75..8255d7b4200 100644
--- a/tests/ui/for-loop-while/for-loop-no-std.rs
+++ b/tests/ui/for-loop-while/for-loop-no-std.rs
@@ -1,14 +1,19 @@
 //@ run-pass
+//@ ignore-emscripten no no_std executables
+//@ ignore-wasm different `main` convention
 #![allow(unused_imports)]
-#![feature(lang_items, start)]
 #![no_std]
+#![no_main]
 
+// Import global allocator and panic handler.
 extern crate std as other;
 
 #[macro_use] extern crate alloc;
 
-#[start]
-fn start(_argc: isize, _argv: *const *const u8) -> isize {
+use alloc::string::ToString;
+
+#[no_mangle]
+extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int {
     for _ in [1,2,3].iter() { }
     0
 }
diff --git a/tests/ui/for-loop-while/while-let-2.stderr b/tests/ui/for-loop-while/while-let-2.stderr
index 1b1cf679243..355ae6f718e 100644
--- a/tests/ui/for-loop-while/while-let-2.stderr
+++ b/tests/ui/for-loop-while/while-let-2.stderr
@@ -2,7 +2,7 @@ warning: irrefutable `while let` pattern
   --> $DIR/while-let-2.rs:7:19
    |
 LL |               while let $p = $e $b
-   |                     ^^^
+   |                     ^^^^^^^^^^^
 ...
 LL | /     foo!(_a, 1, {
 LL | |         println!("irrefutable pattern");
diff --git a/tests/ui/format-no-std.rs b/tests/ui/format-no-std.rs
index 27c31f48a00..657b210a9a0 100644
--- a/tests/ui/format-no-std.rs
+++ b/tests/ui/format-no-std.rs
@@ -1,17 +1,20 @@
 //@ run-pass
 //@ ignore-emscripten no no_std executables
+//@ ignore-wasm different `main` convention
 
-#![feature(lang_items, start)]
+#![feature(lang_items)]
 #![no_std]
+#![no_main]
 
+// Import global allocator and panic handler.
 extern crate std as other;
 
 #[macro_use] extern crate alloc;
 
 use alloc::string::ToString;
 
-#[start]
-fn start(_argc: isize, _argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int {
     let s = format!("{}", 1_isize);
     assert_eq!(s, "1".to_string());
 
diff --git a/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.rs b/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.rs
index 1a4678c7e70..b02739a7d0a 100644
--- a/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.rs
+++ b/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.rs
@@ -8,5 +8,5 @@ fn main() {
     //~| ERROR: binding for associated type `Y` references lifetime
     //~| ERROR: binding for associated type `Y` references lifetime
     //~| ERROR: binding for associated type `Y` references lifetime
-    //~| ERROR: the trait `X` cannot be made into an object
+    //~| ERROR: the trait `X` is not dyn compatible
 }
diff --git a/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr b/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr
index 867f55b0dee..4c5a47e73c6 100644
--- a/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr
+++ b/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr
@@ -36,17 +36,18 @@ LL |   fn _f(arg : Box<dyn for<'a> X<Y<'x> = &'a [u32]>>) {}
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0038]: the trait `X` cannot be made into an object
+error[E0038]: the trait `X` is not dyn compatible
   --> $DIR/gat-in-trait-path-undeclared-lifetime.rs:6:19
    |
 LL |   fn _f(arg : Box<dyn for<'a> X<Y<'x> = &'a [u32]>>) {}
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/gat-in-trait-path-undeclared-lifetime.rs:2:8
    |
 LL | trait X {
-   |       - this trait cannot be made into an object...
+   |       - this trait is not dyn compatible...
 LL |   type Y<'x>;
    |        ^ ...because it contains the generic associated type `Y`
    = help: consider moving `Y` to another trait
diff --git a/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr b/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr
index 34642f8fdc6..b2b569e6261 100644
--- a/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr
+++ b/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr
@@ -1,56 +1,50 @@
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/gat-in-trait-path.rs:26:17
    |
 LL | fn f(_arg : Box<dyn for<'a> Foo<A<'a> = &'a ()>>) {}
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/gat-in-trait-path.rs:10:10
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     type A<'a> where Self: 'a;
    |          ^ ...because it contains the generic associated type `A`
    = help: consider moving `A` to another trait
-   = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Foo` for this new enum and using it instead:
-             Fooy
-             Fooer<T>
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/gat-in-trait-path.rs:32:5
    |
 LL |   f(Box::new(foo));
-   |     ^^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |     ^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/gat-in-trait-path.rs:10:10
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     type A<'a> where Self: 'a;
    |          ^ ...because it contains the generic associated type `A`
    = help: consider moving `A` to another trait
-   = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Foo` for this new enum and using it instead:
-             Fooy
-             Fooer<T>
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/gat-in-trait-path.rs:32:5
    |
 LL |   f(Box::new(foo));
-   |     ^^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |     ^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/gat-in-trait-path.rs:10:10
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     type A<'a> where Self: 'a;
    |          ^ ...because it contains the generic associated type `A`
    = help: consider moving `A` to another trait
-   = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Foo` for this new enum and using it instead:
-             Fooy
-             Fooer<T>
    = note: required for the cast from `Box<Fooer<{integer}>>` to `Box<(dyn Foo<A<'a> = &'a ()> + 'static)>`
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/generic-associated-types/gat-in-trait-path.rs b/tests/ui/generic-associated-types/gat-in-trait-path.rs
index cd759a73cf2..24cae213e0a 100644
--- a/tests/ui/generic-associated-types/gat-in-trait-path.rs
+++ b/tests/ui/generic-associated-types/gat-in-trait-path.rs
@@ -20,12 +20,11 @@ impl<T> Foo for Fooer<T> {
 }
 
 fn f(_arg : Box<dyn for<'a> Foo<A<'a> = &'a ()>>) {}
-//~^ the trait `Foo` cannot be made into an object
-
+//~^ the trait `Foo` is not dyn compatible
 
 fn main() {
   let foo = Fooer(5);
   f(Box::new(foo));
-  //~^ the trait `Foo` cannot be made into an object
-  //~| the trait `Foo` cannot be made into an object
+  //~^ the trait `Foo` is not dyn compatible
+  //~| the trait `Foo` is not dyn compatible
 }
diff --git a/tests/ui/generic-associated-types/gat-in-trait-path.stderr b/tests/ui/generic-associated-types/gat-in-trait-path.stderr
index b2176fa6de3..df79556c825 100644
--- a/tests/ui/generic-associated-types/gat-in-trait-path.stderr
+++ b/tests/ui/generic-associated-types/gat-in-trait-path.stderr
@@ -1,56 +1,50 @@
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/gat-in-trait-path.rs:22:17
    |
 LL | fn f(_arg : Box<dyn for<'a> Foo<A<'a> = &'a ()>>) {}
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/gat-in-trait-path.rs:6:10
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     type A<'a> where Self: 'a;
    |          ^ ...because it contains the generic associated type `A`
    = help: consider moving `A` to another trait
-   = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Foo` for this new enum and using it instead:
-             Fooy
-             Fooer<T>
 
-error[E0038]: the trait `Foo` cannot be made into an object
-  --> $DIR/gat-in-trait-path.rs:28:5
+error[E0038]: the trait `Foo` is not dyn compatible
+  --> $DIR/gat-in-trait-path.rs:27:5
    |
 LL |   f(Box::new(foo));
-   |     ^^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |     ^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/gat-in-trait-path.rs:6:10
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     type A<'a> where Self: 'a;
    |          ^ ...because it contains the generic associated type `A`
    = help: consider moving `A` to another trait
-   = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Foo` for this new enum and using it instead:
-             Fooy
-             Fooer<T>
 
-error[E0038]: the trait `Foo` cannot be made into an object
-  --> $DIR/gat-in-trait-path.rs:28:5
+error[E0038]: the trait `Foo` is not dyn compatible
+  --> $DIR/gat-in-trait-path.rs:27:5
    |
 LL |   f(Box::new(foo));
-   |     ^^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |     ^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/gat-in-trait-path.rs:6:10
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     type A<'a> where Self: 'a;
    |          ^ ...because it contains the generic associated type `A`
    = help: consider moving `A` to another trait
-   = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Foo` for this new enum and using it instead:
-             Fooy
-             Fooer<T>
    = note: required for the cast from `Box<Fooer<{integer}>>` to `Box<(dyn Foo<A<'a> = &'a ()> + 'static)>`
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs
index c4134427013..85661c1b844 100644
--- a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs
+++ b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs
@@ -12,7 +12,7 @@ fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
   //~| ERROR associated type takes 0 generic arguments but 1 generic argument
   //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments
   //~| ERROR at least one trait is required
-  //~| ERROR: the trait `X` cannot be made into an object
+  //~| ERROR: the trait `X` is not dyn compatible
 
 
 fn bar<'a>(arg: Box<dyn X<Y() = ()>>) {}
@@ -20,6 +20,6 @@ fn bar<'a>(arg: Box<dyn X<Y() = ()>>) {}
   //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments
   //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments
   //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments
-  //~| ERROR: the trait `X` cannot be made into an object
+  //~| ERROR: the trait `X` is not dyn compatible
 
 fn main() {}
diff --git a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
index 97b7019b385..499ce8e4a32 100644
--- a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
+++ b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
@@ -123,17 +123,18 @@ error[E0224]: at least one trait is required for an object type
 LL | fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
    |                             ^^
 
-error[E0038]: the trait `X` cannot be made into an object
+error[E0038]: the trait `X` is not dyn compatible
   --> $DIR/gat-trait-path-parenthesised-args.rs:5:21
    |
 LL | fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
-   |                     ^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object
+   |                     ^^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/gat-trait-path-parenthesised-args.rs:2:8
    |
 LL | trait X {
-   |       - this trait cannot be made into an object...
+   |       - this trait is not dyn compatible...
 LL |   type Y<'a>;
    |        ^ ...because it contains the generic associated type `Y`
    = help: consider moving `Y` to another trait
@@ -188,17 +189,18 @@ help: add missing lifetime argument
 LL | fn bar<'a>(arg: Box<dyn X<Y('_) = ()>>) {}
    |                             ++
 
-error[E0038]: the trait `X` cannot be made into an object
+error[E0038]: the trait `X` is not dyn compatible
   --> $DIR/gat-trait-path-parenthesised-args.rs:18:21
    |
 LL | fn bar<'a>(arg: Box<dyn X<Y() = ()>>) {}
-   |                     ^^^^^^^^^^^^^^^ `X` cannot be made into an object
+   |                     ^^^^^^^^^^^^^^^ `X` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/gat-trait-path-parenthesised-args.rs:2:8
    |
 LL | trait X {
-   |       - this trait cannot be made into an object...
+   |       - this trait is not dyn compatible...
 LL |   type Y<'a>;
    |        ^ ...because it contains the generic associated type `Y`
    = help: consider moving `Y` to another trait
diff --git a/tests/ui/generic-associated-types/issue-67510-pass.base.stderr b/tests/ui/generic-associated-types/issue-67510-pass.base.stderr
index cac8010018e..56308948969 100644
--- a/tests/ui/generic-associated-types/issue-67510-pass.base.stderr
+++ b/tests/ui/generic-associated-types/issue-67510-pass.base.stderr
@@ -1,14 +1,15 @@
-error[E0038]: the trait `X` cannot be made into an object
+error[E0038]: the trait `X` is not dyn compatible
   --> $DIR/issue-67510-pass.rs:12:23
    |
 LL | fn _func1<'a>(_x: Box<dyn X<Y<'a>=&'a ()>>) {}
-   |                       ^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object
+   |                       ^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-67510-pass.rs:9:10
    |
 LL | trait X {
-   |       - this trait cannot be made into an object...
+   |       - this trait is not dyn compatible...
 LL |     type Y<'a>;
    |          ^ ...because it contains the generic associated type `Y`
    = help: consider moving `Y` to another trait
diff --git a/tests/ui/generic-associated-types/issue-67510-pass.rs b/tests/ui/generic-associated-types/issue-67510-pass.rs
index a48d9c37cd4..2bfba7f6942 100644
--- a/tests/ui/generic-associated-types/issue-67510-pass.rs
+++ b/tests/ui/generic-associated-types/issue-67510-pass.rs
@@ -5,6 +5,6 @@ trait X {
 }
 
 fn _func1<'a>(_x: Box<dyn X<Y<'a>=&'a ()>>) {}
-//~^ ERROR the trait `X` cannot be made into an object
+//~^ ERROR the trait `X` is not dyn compatible
 
 fn main() {}
diff --git a/tests/ui/generic-associated-types/issue-67510-pass.stderr b/tests/ui/generic-associated-types/issue-67510-pass.stderr
index 5560cb0f64d..f6846f833fe 100644
--- a/tests/ui/generic-associated-types/issue-67510-pass.stderr
+++ b/tests/ui/generic-associated-types/issue-67510-pass.stderr
@@ -1,14 +1,15 @@
-error[E0038]: the trait `X` cannot be made into an object
+error[E0038]: the trait `X` is not dyn compatible
   --> $DIR/issue-67510-pass.rs:7:23
    |
 LL | fn _func1<'a>(_x: Box<dyn X<Y<'a>=&'a ()>>) {}
-   |                       ^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object
+   |                       ^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-67510-pass.rs:4:10
    |
 LL | trait X {
-   |       - this trait cannot be made into an object...
+   |       - this trait is not dyn compatible...
 LL |     type Y<'a>;
    |          ^ ...because it contains the generic associated type `Y`
    = help: consider moving `Y` to another trait
diff --git a/tests/ui/generic-associated-types/issue-67510.rs b/tests/ui/generic-associated-types/issue-67510.rs
index ab5c25d74da..5c3150a77ed 100644
--- a/tests/ui/generic-associated-types/issue-67510.rs
+++ b/tests/ui/generic-associated-types/issue-67510.rs
@@ -5,6 +5,6 @@ trait X {
 fn f(x: Box<dyn X<Y<'a> = &'a ()>>) {}
 //~^ ERROR: use of undeclared lifetime name `'a`
 //~| ERROR: use of undeclared lifetime name `'a`
-//~| ERROR: the trait `X` cannot be made into an object [E0038]
+//~| ERROR: the trait `X` is not dyn compatible [E0038]
 
 fn main() {}
diff --git a/tests/ui/generic-associated-types/issue-67510.stderr b/tests/ui/generic-associated-types/issue-67510.stderr
index 416f04ac2fd..e8555a7aa1f 100644
--- a/tests/ui/generic-associated-types/issue-67510.stderr
+++ b/tests/ui/generic-associated-types/issue-67510.stderr
@@ -29,17 +29,18 @@ help: consider introducing lifetime `'a` here
 LL | fn f<'a>(x: Box<dyn X<Y<'a> = &'a ()>>) {}
    |     ++++
 
-error[E0038]: the trait `X` cannot be made into an object
+error[E0038]: the trait `X` is not dyn compatible
   --> $DIR/issue-67510.rs:5:13
    |
 LL | fn f(x: Box<dyn X<Y<'a> = &'a ()>>) {}
-   |             ^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object
+   |             ^^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-67510.rs:2:10
    |
 LL | trait X {
-   |       - this trait cannot be made into an object...
+   |       - this trait is not dyn compatible...
 LL |     type Y<'a>;
    |          ^ ...because it contains the generic associated type `Y`
    = help: consider moving `Y` to another trait
diff --git a/tests/ui/generic-associated-types/issue-71176.rs b/tests/ui/generic-associated-types/issue-71176.rs
index 7fffe312f4b..d3a0caffec1 100644
--- a/tests/ui/generic-associated-types/issue-71176.rs
+++ b/tests/ui/generic-associated-types/issue-71176.rs
@@ -11,13 +11,13 @@ struct Holder<B> {
   //~^ ERROR: missing generics for associated type
   //~| ERROR: missing generics for associated type
   //~| ERROR: missing generics for associated type
-  //~| ERROR: the trait `Provider` cannot be made into an object
+  //~| ERROR: the trait `Provider` is not dyn compatible
 }
 
 fn main() {
     Holder {
         inner: Box::new(()),
-        //~^ ERROR: the trait `Provider` cannot be made into an object
-        //~| ERROR: the trait `Provider` cannot be made into an object
+        //~^ ERROR: the trait `Provider` is not dyn compatible
+        //~| ERROR: the trait `Provider` is not dyn compatible
     };
 }
diff --git a/tests/ui/generic-associated-types/issue-71176.stderr b/tests/ui/generic-associated-types/issue-71176.stderr
index 1cd2ed0d313..a78151384d4 100644
--- a/tests/ui/generic-associated-types/issue-71176.stderr
+++ b/tests/ui/generic-associated-types/issue-71176.stderr
@@ -48,53 +48,56 @@ help: add missing lifetime argument
 LL |   inner: Box<dyn Provider<A<'a> = B>>,
    |                            ++++
 
-error[E0038]: the trait `Provider` cannot be made into an object
+error[E0038]: the trait `Provider` is not dyn compatible
   --> $DIR/issue-71176.rs:10:14
    |
 LL |   inner: Box<dyn Provider<A = B>>,
-   |              ^^^^^^^^^^^^^^^^^^^ `Provider` cannot be made into an object
+   |              ^^^^^^^^^^^^^^^^^^^ `Provider` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-71176.rs:2:10
    |
 LL | trait Provider {
-   |       -------- this trait cannot be made into an object...
+   |       -------- this trait is not dyn compatible...
 LL |     type A<'a>;
    |          ^ ...because it contains the generic associated type `A`
    = help: consider moving `A` to another trait
-   = help: only type `()` implements the trait, consider using it directly instead
+   = help: only type `()` implements `Provider`; consider using it directly instead.
 
-error[E0038]: the trait `Provider` cannot be made into an object
+error[E0038]: the trait `Provider` is not dyn compatible
   --> $DIR/issue-71176.rs:19:16
    |
 LL |         inner: Box::new(()),
-   |                ^^^^^^^^^^^^ `Provider` cannot be made into an object
+   |                ^^^^^^^^^^^^ `Provider` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-71176.rs:2:10
    |
 LL | trait Provider {
-   |       -------- this trait cannot be made into an object...
+   |       -------- this trait is not dyn compatible...
 LL |     type A<'a>;
    |          ^ ...because it contains the generic associated type `A`
    = help: consider moving `A` to another trait
-   = help: only type `()` implements the trait, consider using it directly instead
+   = help: only type `()` implements `Provider`; consider using it directly instead.
 
-error[E0038]: the trait `Provider` cannot be made into an object
+error[E0038]: the trait `Provider` is not dyn compatible
   --> $DIR/issue-71176.rs:19:16
    |
 LL |         inner: Box::new(()),
-   |                ^^^^^^^^^^^^ `Provider` cannot be made into an object
+   |                ^^^^^^^^^^^^ `Provider` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-71176.rs:2:10
    |
 LL | trait Provider {
-   |       -------- this trait cannot be made into an object...
+   |       -------- this trait is not dyn compatible...
 LL |     type A<'a>;
    |          ^ ...because it contains the generic associated type `A`
    = help: consider moving `A` to another trait
-   = help: only type `()` implements the trait, consider using it directly instead
+   = help: only type `()` implements `Provider`; consider using it directly instead.
    = note: required for the cast from `Box<()>` to `Box<(dyn Provider<A<'_> = _> + 'static), {type error}>`
 
 error: aborting due to 6 previous errors
diff --git a/tests/ui/generic-associated-types/issue-76535.base.stderr b/tests/ui/generic-associated-types/issue-76535.base.stderr
index a44c8dc51e7..b503fad2d84 100644
--- a/tests/ui/generic-associated-types/issue-76535.base.stderr
+++ b/tests/ui/generic-associated-types/issue-76535.base.stderr
@@ -14,39 +14,41 @@ help: add missing lifetime argument
 LL |     let sub: Box<dyn SuperTrait<SubType<'a> = SubStruct>> = Box::new(SuperStruct::new(0));
    |                                        ++++
 
-error[E0038]: the trait `SuperTrait` cannot be made into an object
+error[E0038]: the trait `SuperTrait` is not dyn compatible
   --> $DIR/issue-76535.rs:39:14
    |
 LL |     let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-76535.rs:9:10
    |
 LL | pub trait SuperTrait {
-   |           ---------- this trait cannot be made into an object...
+   |           ---------- this trait is not dyn compatible...
 LL |     type SubType<'a>: SubTrait where Self: 'a;
    |          ^^^^^^^ ...because it contains the generic associated type `SubType`
    = help: consider moving `SubType` to another trait
-   = help: only type `SuperStruct` is seen to implement the trait in this crate, consider using it directly instead
-   = note: `SuperTrait` can be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type
+   = help: only type `SuperStruct` implements `SuperTrait` within this crate. Consider using it directly instead.
+   = note: `SuperTrait` may be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type
 
-error[E0038]: the trait `SuperTrait` cannot be made into an object
+error[E0038]: the trait `SuperTrait` is not dyn compatible
   --> $DIR/issue-76535.rs:39:57
    |
 LL |     let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
-   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
+   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-76535.rs:9:10
    |
 LL | pub trait SuperTrait {
-   |           ---------- this trait cannot be made into an object...
+   |           ---------- this trait is not dyn compatible...
 LL |     type SubType<'a>: SubTrait where Self: 'a;
    |          ^^^^^^^ ...because it contains the generic associated type `SubType`
    = help: consider moving `SubType` to another trait
-   = help: only type `SuperStruct` is seen to implement the trait in this crate, consider using it directly instead
-   = note: `SuperTrait` can be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type
+   = help: only type `SuperStruct` implements `SuperTrait` within this crate. Consider using it directly instead.
+   = note: `SuperTrait` may be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type
    = note: required for the cast from `Box<SuperStruct>` to `Box<dyn SuperTrait<SubType<'_> = SubStruct<'_>>>`
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/generic-associated-types/issue-76535.stderr b/tests/ui/generic-associated-types/issue-76535.stderr
index 613ded6f1ef..6b7c3bfe731 100644
--- a/tests/ui/generic-associated-types/issue-76535.stderr
+++ b/tests/ui/generic-associated-types/issue-76535.stderr
@@ -14,39 +14,41 @@ help: add missing lifetime argument
 LL |     let sub: Box<dyn SuperTrait<SubType<'a> = SubStruct>> = Box::new(SuperStruct::new(0));
    |                                        ++++
 
-error[E0038]: the trait `SuperTrait` cannot be made into an object
+error[E0038]: the trait `SuperTrait` is not dyn compatible
   --> $DIR/issue-76535.rs:34:14
    |
 LL |     let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-76535.rs:4:10
    |
 LL | pub trait SuperTrait {
-   |           ---------- this trait cannot be made into an object...
+   |           ---------- this trait is not dyn compatible...
 LL |     type SubType<'a>: SubTrait where Self: 'a;
    |          ^^^^^^^ ...because it contains the generic associated type `SubType`
    = help: consider moving `SubType` to another trait
-   = help: only type `SuperStruct` is seen to implement the trait in this crate, consider using it directly instead
-   = note: `SuperTrait` can be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type
+   = help: only type `SuperStruct` implements `SuperTrait` within this crate; consider using it directly instead.
+   = note: `SuperTrait` may be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type
 
-error[E0038]: the trait `SuperTrait` cannot be made into an object
+error[E0038]: the trait `SuperTrait` is not dyn compatible
   --> $DIR/issue-76535.rs:34:57
    |
 LL |     let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
-   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
+   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-76535.rs:4:10
    |
 LL | pub trait SuperTrait {
-   |           ---------- this trait cannot be made into an object...
+   |           ---------- this trait is not dyn compatible...
 LL |     type SubType<'a>: SubTrait where Self: 'a;
    |          ^^^^^^^ ...because it contains the generic associated type `SubType`
    = help: consider moving `SubType` to another trait
-   = help: only type `SuperStruct` is seen to implement the trait in this crate, consider using it directly instead
-   = note: `SuperTrait` can be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type
+   = help: only type `SuperStruct` implements `SuperTrait` within this crate; consider using it directly instead.
+   = note: `SuperTrait` may be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type
    = note: required for the cast from `Box<SuperStruct>` to `Box<dyn SuperTrait<SubType<'_> = SubStruct<'_>>>`
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/generic-associated-types/issue-78671.base.stderr b/tests/ui/generic-associated-types/issue-78671.base.stderr
index 9f2be785460..9bfe8c0b956 100644
--- a/tests/ui/generic-associated-types/issue-78671.base.stderr
+++ b/tests/ui/generic-associated-types/issue-78671.base.stderr
@@ -14,17 +14,18 @@ help: add missing generic argument
 LL |     Box::new(Family) as &dyn CollectionFamily<Member<T>=usize>
    |                                                     +++
 
-error[E0038]: the trait `CollectionFamily` cannot be made into an object
+error[E0038]: the trait `CollectionFamily` is not dyn compatible
   --> $DIR/issue-78671.rs:10:25
    |
 LL |     Box::new(Family) as &dyn CollectionFamily<Member=usize>
-   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CollectionFamily` cannot be made into an object
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CollectionFamily` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-78671.rs:7:10
    |
 LL | trait CollectionFamily {
-   |       ---------------- this trait cannot be made into an object...
+   |       ---------------- this trait is not dyn compatible...
 LL |     type Member<T>;
    |          ^^^^^^ ...because it contains the generic associated type `Member`
    = help: consider moving `Member` to another trait
diff --git a/tests/ui/generic-associated-types/issue-78671.rs b/tests/ui/generic-associated-types/issue-78671.rs
index 0871def1731..1e1863799a5 100644
--- a/tests/ui/generic-associated-types/issue-78671.rs
+++ b/tests/ui/generic-associated-types/issue-78671.rs
@@ -4,7 +4,7 @@ trait CollectionFamily {
 fn floatify() {
     Box::new(Family) as &dyn CollectionFamily<Member=usize>
     //~^ ERROR: missing generics for associated type
-    //~| ERROR: the trait `CollectionFamily` cannot be made into an object
+    //~| ERROR: the trait `CollectionFamily` is not dyn compatible
 }
 
 struct Family;
diff --git a/tests/ui/generic-associated-types/issue-78671.stderr b/tests/ui/generic-associated-types/issue-78671.stderr
index fbd76c73895..c85e97067cb 100644
--- a/tests/ui/generic-associated-types/issue-78671.stderr
+++ b/tests/ui/generic-associated-types/issue-78671.stderr
@@ -14,17 +14,18 @@ help: add missing generic argument
 LL |     Box::new(Family) as &dyn CollectionFamily<Member<T>=usize>
    |                                                     +++
 
-error[E0038]: the trait `CollectionFamily` cannot be made into an object
+error[E0038]: the trait `CollectionFamily` is not dyn compatible
   --> $DIR/issue-78671.rs:5:25
    |
 LL |     Box::new(Family) as &dyn CollectionFamily<Member=usize>
-   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CollectionFamily` cannot be made into an object
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CollectionFamily` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-78671.rs:2:10
    |
 LL | trait CollectionFamily {
-   |       ---------------- this trait cannot be made into an object...
+   |       ---------------- this trait is not dyn compatible...
 LL |     type Member<T>;
    |          ^^^^^^ ...because it contains the generic associated type `Member`
    = help: consider moving `Member` to another trait
diff --git a/tests/ui/generic-associated-types/issue-79422.base.stderr b/tests/ui/generic-associated-types/issue-79422.base.stderr
index 3ea62bdbb27..c3de2b71762 100644
--- a/tests/ui/generic-associated-types/issue-79422.base.stderr
+++ b/tests/ui/generic-associated-types/issue-79422.base.stderr
@@ -14,41 +14,37 @@ help: add missing lifetime argument
 LL |         as Box<dyn MapLike<u8, u8, VRefCont<'a> = dyn RefCont<'_, u8>>>;
    |                                            ++++
 
-error[E0038]: the trait `MapLike` cannot be made into an object
+error[E0038]: the trait `MapLike` is not dyn compatible
   --> $DIR/issue-79422.rs:47:12
    |
 LL |         as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>;
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-79422.rs:23:10
    |
 LL | trait MapLike<K, V> {
-   |       ------- this trait cannot be made into an object...
+   |       ------- this trait is not dyn compatible...
 LL |     type VRefCont<'a>: RefCont<'a, V> where Self: 'a;
    |          ^^^^^^^^ ...because it contains the generic associated type `VRefCont`
    = help: consider moving `VRefCont` to another trait
-   = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `MapLike` for this new enum and using it instead:
-             std::collections::BTreeMap<K, V>
-             Source
 
-error[E0038]: the trait `MapLike` cannot be made into an object
+error[E0038]: the trait `MapLike` is not dyn compatible
   --> $DIR/issue-79422.rs:44:13
    |
 LL |     let m = Box::new(std::collections::BTreeMap::<u8, u8>::new())
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-79422.rs:23:10
    |
 LL | trait MapLike<K, V> {
-   |       ------- this trait cannot be made into an object...
+   |       ------- this trait is not dyn compatible...
 LL |     type VRefCont<'a>: RefCont<'a, V> where Self: 'a;
    |          ^^^^^^^^ ...because it contains the generic associated type `VRefCont`
    = help: consider moving `VRefCont` to another trait
-   = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `MapLike` for this new enum and using it instead:
-             std::collections::BTreeMap<K, V>
-             Source
    = note: required for the cast from `Box<BTreeMap<u8, u8>>` to `Box<dyn MapLike<u8, u8, VRefCont<'_> = (dyn RefCont<'_, u8> + 'static)>>`
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/generic-associated-types/issue-79422.stderr b/tests/ui/generic-associated-types/issue-79422.stderr
index 26567e5e927..a81217e96c3 100644
--- a/tests/ui/generic-associated-types/issue-79422.stderr
+++ b/tests/ui/generic-associated-types/issue-79422.stderr
@@ -14,41 +14,37 @@ help: add missing lifetime argument
 LL |         as Box<dyn MapLike<u8, u8, VRefCont<'a> = dyn RefCont<'_, u8>>>;
    |                                            ++++
 
-error[E0038]: the trait `MapLike` cannot be made into an object
+error[E0038]: the trait `MapLike` is not dyn compatible
   --> $DIR/issue-79422.rs:41:12
    |
 LL |         as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>;
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-79422.rs:18:10
    |
 LL | trait MapLike<K, V> {
-   |       ------- this trait cannot be made into an object...
+   |       ------- this trait is not dyn compatible...
 LL |     type VRefCont<'a>: RefCont<'a, V> where Self: 'a;
    |          ^^^^^^^^ ...because it contains the generic associated type `VRefCont`
    = help: consider moving `VRefCont` to another trait
-   = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `MapLike` for this new enum and using it instead:
-             std::collections::BTreeMap<K, V>
-             Source
 
-error[E0038]: the trait `MapLike` cannot be made into an object
+error[E0038]: the trait `MapLike` is not dyn compatible
   --> $DIR/issue-79422.rs:39:13
    |
 LL |     let m = Box::new(std::collections::BTreeMap::<u8, u8>::new())
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-79422.rs:18:10
    |
 LL | trait MapLike<K, V> {
-   |       ------- this trait cannot be made into an object...
+   |       ------- this trait is not dyn compatible...
 LL |     type VRefCont<'a>: RefCont<'a, V> where Self: 'a;
    |          ^^^^^^^^ ...because it contains the generic associated type `VRefCont`
    = help: consider moving `VRefCont` to another trait
-   = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `MapLike` for this new enum and using it instead:
-             std::collections::BTreeMap<K, V>
-             Source
    = note: required for the cast from `Box<BTreeMap<u8, u8>>` to `Box<dyn MapLike<u8, u8, VRefCont<'_> = (dyn RefCont<'_, u8> + 'static)>>`
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/generic-associated-types/missing_lifetime_args.rs b/tests/ui/generic-associated-types/missing_lifetime_args.rs
index 470db5412b2..e0f2db5eb21 100644
--- a/tests/ui/generic-associated-types/missing_lifetime_args.rs
+++ b/tests/ui/generic-associated-types/missing_lifetime_args.rs
@@ -12,7 +12,7 @@ fn foo<'c, 'd>(_arg: Box<dyn X<Y = (&'c u32, &'d u32)>>) {}
 //~^ ERROR missing generics for associated type
 //~| ERROR missing generics for associated type
 //~| ERROR missing generics for associated type
-//~| ERROR the trait `X` cannot be made into an object
+//~| ERROR the trait `X` is not dyn compatible
 
 fn bar<'a, 'b, 'c>(_arg: Foo<'a, 'b>) {}
 //~^ ERROR struct takes 3 lifetime arguments but 2 lifetime
diff --git a/tests/ui/generic-associated-types/missing_lifetime_args.stderr b/tests/ui/generic-associated-types/missing_lifetime_args.stderr
index 61cf4f3dd4a..6b8df5cc12f 100644
--- a/tests/ui/generic-associated-types/missing_lifetime_args.stderr
+++ b/tests/ui/generic-associated-types/missing_lifetime_args.stderr
@@ -48,17 +48,18 @@ help: add missing lifetime arguments
 LL | fn foo<'c, 'd>(_arg: Box<dyn X<Y<'_, '_> = (&'c u32, &'d u32)>>) {}
    |                                 ++++++++
 
-error[E0038]: the trait `X` cannot be made into an object
+error[E0038]: the trait `X` is not dyn compatible
   --> $DIR/missing_lifetime_args.rs:11:26
    |
 LL | fn foo<'c, 'd>(_arg: Box<dyn X<Y = (&'c u32, &'d u32)>>) {}
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/missing_lifetime_args.rs:2:10
    |
 LL | trait X {
-   |       - this trait cannot be made into an object...
+   |       - this trait is not dyn compatible...
 LL |     type Y<'a, 'b>;
    |          ^ ...because it contains the generic associated type `Y`
    = help: consider moving `Y` to another trait
diff --git a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs
index d6fc3df1026..c828691bb30 100644
--- a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs
+++ b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs
@@ -10,7 +10,7 @@ const _: () = {
       //~| ERROR associated type takes 0 generic arguments but 1 generic argument
       //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments
       //~| ERROR associated type takes 0 generic arguments but 1 generic argument
-      //~| ERROR the trait `X` cannot be made into an object
+      //~| ERROR the trait `X` is not dyn compatible
 };
 
 fn main() {}
diff --git a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr
index 91f0f7b3fcf..5c9e9dbe3d7 100644
--- a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr
+++ b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr
@@ -92,17 +92,18 @@ LL |     type Y<'a>;
    |          ^
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0038]: the trait `X` cannot be made into an object
+error[E0038]: the trait `X` is not dyn compatible
   --> $DIR/trait-path-type-error-once-implemented.rs:6:23
    |
 LL |   fn f2<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}
-   |                       ^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object
+   |                       ^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/trait-path-type-error-once-implemented.rs:2:10
    |
 LL | trait X {
-   |       - this trait cannot be made into an object...
+   |       - this trait is not dyn compatible...
 LL |     type Y<'a>;
    |          ^ ...because it contains the generic associated type `Y`
    = help: consider moving `Y` to another trait
diff --git a/tests/ui/generic-associated-types/trait-objects.base.stderr b/tests/ui/generic-associated-types/trait-objects.base.stderr
index 0b5a9b9f7fb..fe9ab165d4a 100644
--- a/tests/ui/generic-associated-types/trait-objects.base.stderr
+++ b/tests/ui/generic-associated-types/trait-objects.base.stderr
@@ -1,44 +1,47 @@
-error[E0038]: the trait `StreamingIterator` cannot be made into an object
+error[E0038]: the trait `StreamingIterator` is not dyn compatible
   --> $DIR/trait-objects.rs:13:21
    |
 LL | fn min_size(x: &mut dyn for<'a> StreamingIterator<Item<'a> = &'a i32>) -> usize {
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/trait-objects.rs:7:10
    |
 LL | trait StreamingIterator {
-   |       ----------------- this trait cannot be made into an object...
+   |       ----------------- this trait is not dyn compatible...
 LL |     type Item<'a> where Self: 'a;
    |          ^^^^ ...because it contains the generic associated type `Item`
    = help: consider moving `Item` to another trait
 
-error[E0038]: the trait `StreamingIterator` cannot be made into an object
+error[E0038]: the trait `StreamingIterator` is not dyn compatible
   --> $DIR/trait-objects.rs:15:7
    |
 LL |     x.size_hint().0
-   |       ^^^^^^^^^ `StreamingIterator` cannot be made into an object
+   |       ^^^^^^^^^ `StreamingIterator` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/trait-objects.rs:7:10
    |
 LL | trait StreamingIterator {
-   |       ----------------- this trait cannot be made into an object...
+   |       ----------------- this trait is not dyn compatible...
 LL |     type Item<'a> where Self: 'a;
    |          ^^^^ ...because it contains the generic associated type `Item`
    = help: consider moving `Item` to another trait
 
-error[E0038]: the trait `StreamingIterator` cannot be made into an object
+error[E0038]: the trait `StreamingIterator` is not dyn compatible
   --> $DIR/trait-objects.rs:15:5
    |
 LL |     x.size_hint().0
-   |     ^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object
+   |     ^^^^^^^^^^^^^ `StreamingIterator` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/trait-objects.rs:7:10
    |
 LL | trait StreamingIterator {
-   |       ----------------- this trait cannot be made into an object...
+   |       ----------------- this trait is not dyn compatible...
 LL |     type Item<'a> where Self: 'a;
    |          ^^^^ ...because it contains the generic associated type `Item`
    = help: consider moving `Item` to another trait
diff --git a/tests/ui/generic-associated-types/trait-objects.rs b/tests/ui/generic-associated-types/trait-objects.rs
index bad9289ee5e..ed324b562e1 100644
--- a/tests/ui/generic-associated-types/trait-objects.rs
+++ b/tests/ui/generic-associated-types/trait-objects.rs
@@ -6,10 +6,10 @@ trait StreamingIterator {
 }
 
 fn min_size(x: &mut dyn for<'a> StreamingIterator<Item<'a> = &'a i32>) -> usize {
-    //~^ the trait `StreamingIterator` cannot be made into an object
+    //~^ the trait `StreamingIterator` is not dyn compatible
     x.size_hint().0
-    //~^ the trait `StreamingIterator` cannot be made into an object
-    //~| the trait `StreamingIterator` cannot be made into an object
+    //~^ the trait `StreamingIterator` is not dyn compatible
+    //~| the trait `StreamingIterator` is not dyn compatible
 }
 
 fn main() {}
diff --git a/tests/ui/generic-associated-types/trait-objects.stderr b/tests/ui/generic-associated-types/trait-objects.stderr
index 3e74776f999..56a1cb1906f 100644
--- a/tests/ui/generic-associated-types/trait-objects.stderr
+++ b/tests/ui/generic-associated-types/trait-objects.stderr
@@ -1,44 +1,47 @@
-error[E0038]: the trait `StreamingIterator` cannot be made into an object
+error[E0038]: the trait `StreamingIterator` is not dyn compatible
   --> $DIR/trait-objects.rs:8:21
    |
 LL | fn min_size(x: &mut dyn for<'a> StreamingIterator<Item<'a> = &'a i32>) -> usize {
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/trait-objects.rs:2:10
    |
 LL | trait StreamingIterator {
-   |       ----------------- this trait cannot be made into an object...
+   |       ----------------- this trait is not dyn compatible...
 LL |     type Item<'a> where Self: 'a;
    |          ^^^^ ...because it contains the generic associated type `Item`
    = help: consider moving `Item` to another trait
 
-error[E0038]: the trait `StreamingIterator` cannot be made into an object
+error[E0038]: the trait `StreamingIterator` is not dyn compatible
   --> $DIR/trait-objects.rs:10:7
    |
 LL |     x.size_hint().0
-   |       ^^^^^^^^^ `StreamingIterator` cannot be made into an object
+   |       ^^^^^^^^^ `StreamingIterator` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/trait-objects.rs:2:10
    |
 LL | trait StreamingIterator {
-   |       ----------------- this trait cannot be made into an object...
+   |       ----------------- this trait is not dyn compatible...
 LL |     type Item<'a> where Self: 'a;
    |          ^^^^ ...because it contains the generic associated type `Item`
    = help: consider moving `Item` to another trait
 
-error[E0038]: the trait `StreamingIterator` cannot be made into an object
+error[E0038]: the trait `StreamingIterator` is not dyn compatible
   --> $DIR/trait-objects.rs:10:5
    |
 LL |     x.size_hint().0
-   |     ^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object
+   |     ^^^^^^^^^^^^^ `StreamingIterator` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/trait-objects.rs:2:10
    |
 LL | trait StreamingIterator {
-   |       ----------------- this trait cannot be made into an object...
+   |       ----------------- this trait is not dyn compatible...
 LL |     type Item<'a> where Self: 'a;
    |          ^^^^ ...because it contains the generic associated type `Item`
    = help: consider moving `Item` to another trait
diff --git a/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.rs b/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.rs
index aeace9f2158..5d039cd5dc6 100644
--- a/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.rs
+++ b/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.rs
@@ -12,8 +12,8 @@ fn needs_bar(_: *mut Type2) {}
 
 fn main() {
     let x: &dyn Foo = &();
-    //~^ ERROR the trait `Foo` cannot be made into an object
-    //~| ERROR the trait `Foo` cannot be made into an object
+    //~^ ERROR the trait `Foo` is not dyn compatible
+    //~| ERROR the trait `Foo` is not dyn compatible
 
     needs_bar(x);
     //~^ ERROR mismatched types
diff --git a/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr b/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr
index d48bf8a471d..fc3d9c2171d 100644
--- a/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr
@@ -1,31 +1,33 @@
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/span-bug-issue-121597.rs:14:23
    |
 LL |     let x: &dyn Foo = &();
-   |                       ^^^ `Foo` cannot be made into an object
+   |                       ^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/span-bug-issue-121597.rs:4:12
    |
 LL | trait Foo: for<T> Bar<T> {}
    |       ---  ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables
    |       |
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
    = note: required for the cast from `&()` to `&dyn Foo`
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/span-bug-issue-121597.rs:14:12
    |
 LL |     let x: &dyn Foo = &();
-   |            ^^^^^^^^ `Foo` cannot be made into an object
+   |            ^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/span-bug-issue-121597.rs:4:12
    |
 LL | trait Foo: for<T> Bar<T> {}
    |       ---  ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables
    |       |
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
 
 error[E0308]: mismatched types
   --> $DIR/span-bug-issue-121597.rs:18:15
diff --git a/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.rs b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.rs
index 76dbb05f53d..046ced072ba 100644
--- a/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.rs
+++ b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.rs
@@ -19,7 +19,7 @@ impl DynIncompatible for B {
     }
 }
 
-fn car() -> dyn DynIncompatible { //~ ERROR the trait `DynIncompatible` cannot be made into an object
+fn car() -> dyn DynIncompatible { //~ ERROR the trait `DynIncompatible` is not dyn compatible
 //~^ ERROR return type cannot have an unboxed trait object
     if true {
         return A;
@@ -27,11 +27,11 @@ fn car() -> dyn DynIncompatible { //~ ERROR the trait `DynIncompatible` cannot b
     B
 }
 
-fn cat() -> Box<dyn DynIncompatible> { //~ ERROR the trait `DynIncompatible` cannot be made into an
+fn cat() -> Box<dyn DynIncompatible> { //~ ERROR the trait `DynIncompatible` is not dyn compatible
     if true {
-        return Box::new(A); //~ ERROR cannot be made into an object
+        return Box::new(A); //~ ERROR is not dyn compatible
     }
-    Box::new(B) //~ ERROR cannot be made into an object
+    Box::new(B) //~ ERROR is not dyn compatible
 }
 
 fn main() {}
diff --git a/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr
index 576bd909cbc..4abd7bcf31c 100644
--- a/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr
+++ b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr
@@ -1,19 +1,22 @@
-error[E0038]: the trait `DynIncompatible` cannot be made into an object
+error[E0038]: the trait `DynIncompatible` is not dyn compatible
   --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:22:13
    |
 LL | fn car() -> dyn DynIncompatible {
-   |             ^^^^^^^^^^^^^^^^^^^ `DynIncompatible` cannot be made into an object
+   |             ^^^^^^^^^^^^^^^^^^^ `DynIncompatible` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:4:8
    |
 LL | trait DynIncompatible {
-   |       --------------- this trait cannot be made into an object...
+   |       --------------- this trait is not dyn compatible...
 LL |     fn foo() -> Self;
    |        ^^^ ...because associated function `foo` has no `self` parameter
-   = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `DynIncompatible` for this new enum and using it instead:
+   = help: the following types implement `DynIncompatible`:
              A
              B
+           consider defining an enum where each variant holds one of these types,
+           implementing `DynIncompatible` for this new enum and using it instead
 help: consider turning `foo` into a method by giving it a `&self` argument
    |
 LL |     fn foo(&self) -> Self;
@@ -23,22 +26,25 @@ help: alternatively, consider constraining `foo` so it does not apply to trait o
 LL |     fn foo() -> Self where Self: Sized;
    |                      +++++++++++++++++
 
-error[E0038]: the trait `DynIncompatible` cannot be made into an object
+error[E0038]: the trait `DynIncompatible` is not dyn compatible
   --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:30:17
    |
 LL | fn cat() -> Box<dyn DynIncompatible> {
-   |                 ^^^^^^^^^^^^^^^^^^^ `DynIncompatible` cannot be made into an object
+   |                 ^^^^^^^^^^^^^^^^^^^ `DynIncompatible` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:4:8
    |
 LL | trait DynIncompatible {
-   |       --------------- this trait cannot be made into an object...
+   |       --------------- this trait is not dyn compatible...
 LL |     fn foo() -> Self;
    |        ^^^ ...because associated function `foo` has no `self` parameter
-   = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `DynIncompatible` for this new enum and using it instead:
+   = help: the following types implement `DynIncompatible`:
              A
              B
+           consider defining an enum where each variant holds one of these types,
+           implementing `DynIncompatible` for this new enum and using it instead
 help: consider turning `foo` into a method by giving it a `&self` argument
    |
 LL |     fn foo(&self) -> Self;
@@ -65,22 +71,25 @@ LL |     }
 LL ~     Box::new(B)
    |
 
-error[E0038]: the trait `DynIncompatible` cannot be made into an object
+error[E0038]: the trait `DynIncompatible` is not dyn compatible
   --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:32:16
    |
 LL |         return Box::new(A);
-   |                ^^^^^^^^^^^ `DynIncompatible` cannot be made into an object
+   |                ^^^^^^^^^^^ `DynIncompatible` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:4:8
    |
 LL | trait DynIncompatible {
-   |       --------------- this trait cannot be made into an object...
+   |       --------------- this trait is not dyn compatible...
 LL |     fn foo() -> Self;
    |        ^^^ ...because associated function `foo` has no `self` parameter
-   = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `DynIncompatible` for this new enum and using it instead:
+   = help: the following types implement `DynIncompatible`:
              A
              B
+           consider defining an enum where each variant holds one of these types,
+           implementing `DynIncompatible` for this new enum and using it instead
    = note: required for the cast from `Box<A>` to `Box<(dyn DynIncompatible + 'static)>`
 help: consider turning `foo` into a method by giving it a `&self` argument
    |
@@ -91,22 +100,25 @@ help: alternatively, consider constraining `foo` so it does not apply to trait o
 LL |     fn foo() -> Self where Self: Sized;
    |                      +++++++++++++++++
 
-error[E0038]: the trait `DynIncompatible` cannot be made into an object
+error[E0038]: the trait `DynIncompatible` is not dyn compatible
   --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:34:5
    |
 LL |     Box::new(B)
-   |     ^^^^^^^^^^^ `DynIncompatible` cannot be made into an object
+   |     ^^^^^^^^^^^ `DynIncompatible` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:4:8
    |
 LL | trait DynIncompatible {
-   |       --------------- this trait cannot be made into an object...
+   |       --------------- this trait is not dyn compatible...
 LL |     fn foo() -> Self;
    |        ^^^ ...because associated function `foo` has no `self` parameter
-   = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `DynIncompatible` for this new enum and using it instead:
+   = help: the following types implement `DynIncompatible`:
              A
              B
+           consider defining an enum where each variant holds one of these types,
+           implementing `DynIncompatible` for this new enum and using it instead
    = note: required for the cast from `Box<B>` to `Box<(dyn DynIncompatible + 'static)>`
 help: consider turning `foo` into a method by giving it a `&self` argument
    |
diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.stderr b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.current.stderr
index 28a0f7461e2..146a3d21068 100644
--- a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.stderr
+++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.current.stderr
@@ -1,11 +1,11 @@
 error[E0407]: method `line_stream` is not a member of trait `X`
-  --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:25:5
+  --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:28:5
    |
 LL |     fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `X`
 
 error[E0049]: type `LineStream` has 0 type parameters but its trait declaration has 1 type parameter
-  --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:22:21
+  --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:25:21
    |
 LL |     type LineStream<'a, Repr>
    |                     --  ----
@@ -18,7 +18,7 @@ LL |     type LineStream<'c, 'd> = impl Stream;
    |                     found 0 type parameters
 
 error[E0277]: `()` is not a future
-  --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:25:43
+  --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:28:43
    |
 LL |     fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}
    |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr
new file mode 100644
index 00000000000..3c24eb9adbe
--- /dev/null
+++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr
@@ -0,0 +1,29 @@
+error[E0407]: method `line_stream` is not a member of trait `X`
+  --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:28:5
+   |
+LL |     fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `X`
+
+error[E0049]: type `LineStream` has 0 type parameters but its trait declaration has 1 type parameter
+  --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:25:21
+   |
+LL |     type LineStream<'a, Repr>
+   |                     --  ----
+   |                     |
+   |                     expected 1 type parameter
+...
+LL |     type LineStream<'c, 'd> = impl Stream;
+   |                     ^^  ^^
+   |                     |
+   |                     found 0 type parameters
+
+error[E0271]: type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()`
+  --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:28:43
+   |
+LL |     fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0049, E0271, E0407.
+For more information about an error, try `rustc --explain E0049`.
diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs
index d6fa56663a3..c97bd179943 100644
--- a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs
+++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs
@@ -1,3 +1,6 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
 // test for ICE #112823
 // Unexpected parameter Type(Repr) when substituting in region
 
@@ -23,8 +26,9 @@ impl X for Y {
     //~^ ERROR type `LineStream` has 0 type parameters but its trait declaration has 1 type parameter
     type LineStreamFut<'a, Repr> = impl Future<Output = Self::LineStream<'a, Repr>>;
     fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}
-    //~^ ERROR `()` is not a future
-    //~^^ method `line_stream` is not a member of trait `X`
+    //[current]~^ ERROR `()` is not a future
+    //[next]~^^ ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()`
+    //~^^^ method `line_stream` is not a member of trait `X`
 }
 
 pub fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.rs b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.rs
index daf29a0005d..d6fa34419d2 100644
--- a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.rs
+++ b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.rs
@@ -14,13 +14,13 @@ impl MyTrait for Outer {
 }
 
 impl dyn MyTrait {
-    //~^ ERROR the trait `MyTrait` cannot be made into an object
+    //~^ ERROR the trait `MyTrait` is not dyn compatible
     fn other(&self) -> impl Marker {
-        //~^ ERROR the trait `MyTrait` cannot be made into an object
+        //~^ ERROR the trait `MyTrait` is not dyn compatible
         MyTrait::foo(&self)
         //~^ ERROR the trait bound `&dyn MyTrait: MyTrait` is not satisfied
         //~| ERROR the trait bound `&dyn MyTrait: MyTrait` is not satisfied
-        //~| ERROR the trait `MyTrait` cannot be made into an object
+        //~| ERROR the trait `MyTrait` is not dyn compatible
     }
 }
 
diff --git a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.stderr b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.stderr
index a975b6204aa..44ca09150fe 100644
--- a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.stderr
+++ b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.stderr
@@ -8,21 +8,22 @@ LL |         MyTrait::foo(&self)
    |
    = help: the trait `MyTrait` is implemented for `Outer`
 
-error[E0038]: the trait `MyTrait` cannot be made into an object
+error[E0038]: the trait `MyTrait` is not dyn compatible
   --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:20:9
    |
 LL |         MyTrait::foo(&self)
-   |         ^^^^^^^^^^^^ `MyTrait` cannot be made into an object
+   |         ^^^^^^^^^^^^ `MyTrait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:5:22
    |
 LL | trait MyTrait {
-   |       ------- this trait cannot be made into an object...
+   |       ------- this trait is not dyn compatible...
 LL |     fn foo(&self) -> impl Marker;
    |                      ^^^^^^^^^^^ ...because method `foo` references an `impl Trait` type in its return type
    = help: consider moving `foo` to another trait
-   = help: only type `Outer` implements the trait, consider using it directly instead
+   = help: only type `Outer` implements `MyTrait`; consider using it directly instead.
 
 error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied
   --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:20:9
@@ -32,37 +33,39 @@ LL |         MyTrait::foo(&self)
    |
    = help: the trait `MyTrait` is implemented for `Outer`
 
-error[E0038]: the trait `MyTrait` cannot be made into an object
+error[E0038]: the trait `MyTrait` is not dyn compatible
   --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:16:6
    |
 LL | impl dyn MyTrait {
-   |      ^^^^^^^^^^^ `MyTrait` cannot be made into an object
+   |      ^^^^^^^^^^^ `MyTrait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:5:22
    |
 LL | trait MyTrait {
-   |       ------- this trait cannot be made into an object...
+   |       ------- this trait is not dyn compatible...
 LL |     fn foo(&self) -> impl Marker;
    |                      ^^^^^^^^^^^ ...because method `foo` references an `impl Trait` type in its return type
    = help: consider moving `foo` to another trait
-   = help: only type `Outer` implements the trait, consider using it directly instead
+   = help: only type `Outer` implements `MyTrait`; consider using it directly instead.
 
-error[E0038]: the trait `MyTrait` cannot be made into an object
+error[E0038]: the trait `MyTrait` is not dyn compatible
   --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:18:15
    |
 LL |     fn other(&self) -> impl Marker {
-   |               ^^^^ `MyTrait` cannot be made into an object
+   |               ^^^^ `MyTrait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:5:22
    |
 LL | trait MyTrait {
-   |       ------- this trait cannot be made into an object...
+   |       ------- this trait is not dyn compatible...
 LL |     fn foo(&self) -> impl Marker;
    |                      ^^^^^^^^^^^ ...because method `foo` references an `impl Trait` type in its return type
    = help: consider moving `foo` to another trait
-   = help: only type `Outer` implements the trait, consider using it directly instead
+   = help: only type `Outer` implements `MyTrait`; consider using it directly instead.
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/impl-trait/in-trait/dyn-compatibility.rs b/tests/ui/impl-trait/in-trait/dyn-compatibility.rs
index 5cca4ad839c..85b1ba269fc 100644
--- a/tests/ui/impl-trait/in-trait/dyn-compatibility.rs
+++ b/tests/ui/impl-trait/in-trait/dyn-compatibility.rs
@@ -12,9 +12,9 @@ impl Foo for u32 {
 
 fn main() {
     let i = Box::new(42_u32) as Box<dyn Foo>;
-    //~^ ERROR the trait `Foo` cannot be made into an object
-    //~| ERROR the trait `Foo` cannot be made into an object
+    //~^ ERROR the trait `Foo` is not dyn compatible
+    //~| ERROR the trait `Foo` is not dyn compatible
     let s = i.baz();
-    //~^ ERROR the trait `Foo` cannot be made into an object
-    //~| ERROR the trait `Foo` cannot be made into an object
+    //~^ ERROR the trait `Foo` is not dyn compatible
+    //~| ERROR the trait `Foo` is not dyn compatible
 }
diff --git a/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr b/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr
index 115cb014b8c..87a5480b1e3 100644
--- a/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr
+++ b/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr
@@ -1,66 +1,70 @@
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/dyn-compatibility.rs:14:33
    |
 LL |     let i = Box::new(42_u32) as Box<dyn Foo>;
-   |                                 ^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |                                 ^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/dyn-compatibility.rs:4:22
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn baz(&self) -> impl Debug;
    |                      ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type
    = help: consider moving `baz` to another trait
-   = help: only type `u32` implements the trait, consider using it directly instead
+   = help: only type `u32` implements `Foo`; consider using it directly instead.
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/dyn-compatibility.rs:17:15
    |
 LL |     let s = i.baz();
-   |               ^^^ `Foo` cannot be made into an object
+   |               ^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/dyn-compatibility.rs:4:22
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn baz(&self) -> impl Debug;
    |                      ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type
    = help: consider moving `baz` to another trait
-   = help: only type `u32` implements the trait, consider using it directly instead
+   = help: only type `u32` implements `Foo`; consider using it directly instead.
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/dyn-compatibility.rs:17:13
    |
 LL |     let s = i.baz();
-   |             ^^^^^^^ `Foo` cannot be made into an object
+   |             ^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/dyn-compatibility.rs:4:22
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn baz(&self) -> impl Debug;
    |                      ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type
    = help: consider moving `baz` to another trait
-   = help: only type `u32` implements the trait, consider using it directly instead
+   = help: only type `u32` implements `Foo`; consider using it directly instead.
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/dyn-compatibility.rs:14:13
    |
 LL |     let i = Box::new(42_u32) as Box<dyn Foo>;
-   |             ^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |             ^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/dyn-compatibility.rs:4:22
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn baz(&self) -> impl Debug;
    |                      ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type
    = help: consider moving `baz` to another trait
-   = help: only type `u32` implements the trait, consider using it directly instead
+   = help: only type `u32` implements `Foo`; consider using it directly instead.
    = note: required for the cast from `Box<u32>` to `Box<dyn Foo>`
 
 error: aborting due to 4 previous errors
diff --git a/tests/ui/impl-trait/in-trait/foreign-dyn-error.rs b/tests/ui/impl-trait/in-trait/foreign-dyn-error.rs
index 600dba03b74..5b891170a4f 100644
--- a/tests/ui/impl-trait/in-trait/foreign-dyn-error.rs
+++ b/tests/ui/impl-trait/in-trait/foreign-dyn-error.rs
@@ -4,5 +4,5 @@ extern crate rpitit;
 
 fn main() {
     let _: &dyn rpitit::Foo = todo!();
-    //~^ ERROR the trait `Foo` cannot be made into an object
+    //~^ ERROR the trait `Foo` is not dyn compatible
 }
diff --git a/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr b/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr
index 895d8686742..07d09468b04 100644
--- a/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr
+++ b/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr
@@ -1,15 +1,16 @@
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/foreign-dyn-error.rs:6:12
    |
 LL |     let _: &dyn rpitit::Foo = todo!();
-   |            ^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |            ^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/auxiliary/rpitit.rs:4:21
    |
 LL |     fn bar(self) -> impl Deref<Target = impl Sized>;
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait cannot be made into an object because method `bar` references an `impl Trait` type in its return type
-   = help: only type `rpitit::Foreign` implements the trait, consider using it directly instead
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait is not dyn compatible because method `bar` references an `impl Trait` type in its return type
+   = help: only type `rpitit::Foreign` implements `Foo`; consider using it directly instead.
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/impl-trait/issue-102605.stderr b/tests/ui/impl-trait/issue-102605.stderr
index dcb22797173..ed6663fa61f 100644
--- a/tests/ui/impl-trait/issue-102605.stderr
+++ b/tests/ui/impl-trait/issue-102605.stderr
@@ -14,20 +14,11 @@ LL |     convert_result(foo())
    |     |
    |     arguments to this function are incorrect
    |
-note: calling an async function returns a future
-  --> $DIR/issue-102605.rs:13:20
-   |
-LL |     convert_result(foo())
-   |                    ^^^^^
 note: function defined here
   --> $DIR/issue-102605.rs:7:4
    |
 LL | fn convert_result<T, E>(r: Result<T, E>) -> Option<T> {
    |    ^^^^^^^^^^^^^^       ---------------
-help: consider `await`ing on the `Future`
-   |
-LL |     convert_result(foo().await)
-   |                         ++++++
 help: try wrapping the expression in `Err`
    |
 LL |     convert_result(Err(foo()))
diff --git a/tests/ui/inference/issue-72616.stderr b/tests/ui/inference/issue-72616.stderr
index 02c92c1c11d..a26f9a1ff56 100644
--- a/tests/ui/inference/issue-72616.stderr
+++ b/tests/ui/inference/issue-72616.stderr
@@ -6,11 +6,14 @@ LL |         if String::from("a") == "a".try_into().unwrap() {}
    |                              |
    |                              type must be known at this point
    |
-   = note: multiple `impl`s satisfying `String: PartialEq<_>` found in the `alloc` crate:
-           - impl PartialEq for String;
-           - impl<'a, 'b> PartialEq<&'a str> for String;
-           - impl<'a, 'b> PartialEq<Cow<'a, str>> for String;
-           - impl<'a, 'b> PartialEq<str> for String;
+   = note: cannot satisfy `String: PartialEq<_>`
+   = help: the following types implement trait `PartialEq<Rhs>`:
+             `String` implements `PartialEq<&str>`
+             `String` implements `PartialEq<ByteStr>`
+             `String` implements `PartialEq<ByteString>`
+             `String` implements `PartialEq<Cow<'_, str>>`
+             `String` implements `PartialEq<str>`
+             `String` implements `PartialEq`
 help: try using a fully qualified path to specify the expected types
    |
 LL |         if String::from("a") == <&str as TryInto<T>>::try_into("a").unwrap() {}
diff --git a/tests/ui/inference/issue-72690.stderr b/tests/ui/inference/issue-72690.stderr
index 6391672f861..2d09f667ae2 100644
--- a/tests/ui/inference/issue-72690.stderr
+++ b/tests/ui/inference/issue-72690.stderr
@@ -15,6 +15,7 @@ LL |     String::from("x".as_ref());
    |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<ByteStr> for str;
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
@@ -41,6 +42,7 @@ LL |     |x| String::from("x".as_ref());
    |                          ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<ByteStr> for str;
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
@@ -57,6 +59,7 @@ LL |     let _ = "x".as_ref();
    |         ^       ------ type must be known at this point
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<ByteStr> for str;
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
@@ -83,6 +86,7 @@ LL |     String::from("x".as_ref());
    |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<ByteStr> for str;
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
@@ -109,6 +113,7 @@ LL |     String::from("x".as_ref());
    |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<ByteStr> for str;
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
@@ -135,6 +140,7 @@ LL |     String::from("x".as_ref());
    |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<ByteStr> for str;
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
@@ -161,6 +167,7 @@ LL |     String::from("x".as_ref());
    |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<ByteStr> for str;
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
@@ -187,6 +194,7 @@ LL |     String::from("x".as_ref());
    |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<ByteStr> for str;
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
@@ -213,6 +221,7 @@ LL |     String::from("x".as_ref());
    |                      ^^^^^^
    |
    = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<ByteStr> for str;
            - impl AsRef<OsStr> for str;
            - impl AsRef<Path> for str;
            - impl AsRef<[u8]> for str;
diff --git a/tests/ui/issues/issue-18959.stderr b/tests/ui/issues/issue-18959.stderr
index 5bb452250aa..49d501c397f 100644
--- a/tests/ui/issues/issue-18959.stderr
+++ b/tests/ui/issues/issue-18959.stderr
@@ -1,77 +1,82 @@
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/issue-18959.rs:11:12
    |
 LL | fn foo(b: &dyn Bar) {
-   |            ^^^^^^^ `Bar` cannot be made into an object
+   |            ^^^^^^^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-18959.rs:1:20
    |
 LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); }
    |                    ^^^ ...because method `foo` has generic type parameters
 LL | pub trait Bar: Foo { }
-   |           --- this trait cannot be made into an object...
+   |           --- this trait is not dyn compatible...
    = help: consider moving `foo` to another trait
 
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/issue-18959.rs:13:5
    |
 LL |     b.foo(&0)
-   |     ^^^^^^^^^ `Bar` cannot be made into an object
+   |     ^^^^^^^^^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-18959.rs:1:20
    |
 LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); }
    |                    ^^^ ...because method `foo` has generic type parameters
 LL | pub trait Bar: Foo { }
-   |           --- this trait cannot be made into an object...
+   |           --- this trait is not dyn compatible...
    = help: consider moving `foo` to another trait
 
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/issue-18959.rs:19:15
    |
 LL |     let test: &dyn Bar = &mut thing;
-   |               ^^^^^^^^ `Bar` cannot be made into an object
+   |               ^^^^^^^^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-18959.rs:1:20
    |
 LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); }
    |                    ^^^ ...because method `foo` has generic type parameters
 LL | pub trait Bar: Foo { }
-   |           --- this trait cannot be made into an object...
+   |           --- this trait is not dyn compatible...
    = help: consider moving `foo` to another trait
 
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/issue-18959.rs:19:26
    |
 LL |     let test: &dyn Bar = &mut thing;
-   |                          ^^^^^^^^^^ `Bar` cannot be made into an object
+   |                          ^^^^^^^^^^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-18959.rs:1:20
    |
 LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); }
    |                    ^^^ ...because method `foo` has generic type parameters
 LL | pub trait Bar: Foo { }
-   |           --- this trait cannot be made into an object...
+   |           --- this trait is not dyn compatible...
    = help: consider moving `foo` to another trait
    = note: required for the cast from `&mut Thing` to `&dyn Bar`
 
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/issue-18959.rs:22:9
    |
 LL |     foo(test);
-   |         ^^^^ `Bar` cannot be made into an object
+   |         ^^^^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-18959.rs:1:20
    |
 LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); }
    |                    ^^^ ...because method `foo` has generic type parameters
 LL | pub trait Bar: Foo { }
-   |           --- this trait cannot be made into an object...
+   |           --- this trait is not dyn compatible...
    = help: consider moving `foo` to another trait
 
 error: aborting due to 5 previous errors
diff --git a/tests/ui/issues/issue-19380.stderr b/tests/ui/issues/issue-19380.stderr
index afbe67befa1..7d4812c3693 100644
--- a/tests/ui/issues/issue-19380.stderr
+++ b/tests/ui/issues/issue-19380.stderr
@@ -1,17 +1,18 @@
-error[E0038]: the trait `Qiz` cannot be made into an object
+error[E0038]: the trait `Qiz` is not dyn compatible
   --> $DIR/issue-19380.rs:11:29
    |
 LL |   foos: &'static [&'static (dyn Qiz + 'static)]
-   |                             ^^^^^^^^^^^^^^^^^ `Qiz` cannot be made into an object
+   |                             ^^^^^^^^^^^^^^^^^ `Qiz` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-19380.rs:2:6
    |
 LL | trait Qiz {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |   fn qiz();
    |      ^^^ ...because associated function `qiz` has no `self` parameter
-   = help: only type `Foo` implements the trait, consider using it directly instead
+   = help: only type `Foo` implements `Qiz`; consider using it directly instead.
 help: consider turning `qiz` into a method by giving it a `&self` argument
    |
 LL |   fn qiz(&self);
@@ -21,20 +22,21 @@ help: alternatively, consider constraining `qiz` so it does not apply to trait o
 LL |   fn qiz() where Self: Sized;
    |            +++++++++++++++++
 
-error[E0038]: the trait `Qiz` cannot be made into an object
+error[E0038]: the trait `Qiz` is not dyn compatible
   --> $DIR/issue-19380.rs:16:33
    |
 LL | const BAR : Bar = Bar { foos: &[&FOO]};
-   |                                 ^^^^ `Qiz` cannot be made into an object
+   |                                 ^^^^ `Qiz` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-19380.rs:2:6
    |
 LL | trait Qiz {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |   fn qiz();
    |      ^^^ ...because associated function `qiz` has no `self` parameter
-   = help: only type `Foo` implements the trait, consider using it directly instead
+   = help: only type `Foo` implements `Qiz`; consider using it directly instead.
    = note: required for the cast from `&Foo` to `&'static (dyn Qiz + 'static)`
 help: consider turning `qiz` into a method by giving it a `&self` argument
    |
@@ -45,20 +47,21 @@ help: alternatively, consider constraining `qiz` so it does not apply to trait o
 LL |   fn qiz() where Self: Sized;
    |            +++++++++++++++++
 
-error[E0038]: the trait `Qiz` cannot be made into an object
+error[E0038]: the trait `Qiz` is not dyn compatible
   --> $DIR/issue-19380.rs:16:31
    |
 LL | const BAR : Bar = Bar { foos: &[&FOO]};
-   |                               ^^^^^^^ `Qiz` cannot be made into an object
+   |                               ^^^^^^^ `Qiz` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-19380.rs:2:6
    |
 LL | trait Qiz {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |   fn qiz();
    |      ^^^ ...because associated function `qiz` has no `self` parameter
-   = help: only type `Foo` implements the trait, consider using it directly instead
+   = help: only type `Foo` implements `Qiz`; consider using it directly instead.
 help: consider turning `qiz` into a method by giving it a `&self` argument
    |
 LL |   fn qiz(&self);
diff --git a/tests/ui/issues/issue-26056.stderr b/tests/ui/issues/issue-26056.stderr
index be5453ec19d..d1cdf43351e 100644
--- a/tests/ui/issues/issue-26056.stderr
+++ b/tests/ui/issues/issue-26056.stderr
@@ -1,16 +1,17 @@
-error[E0038]: the trait `Map` cannot be made into an object
-  --> $DIR/issue-26056.rs:20:13
+error[E0038]: the trait `Map` is not dyn compatible
+  --> $DIR/issue-26056.rs:20:17
    |
 LL |         as &dyn Map<Key=u32,MapValue=u32>;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Map` cannot be made into an object
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^ `Map` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-26056.rs:9:12
    |
 LL | trait Map: MapLookup<<Self as Map>::Key> {
    |       ---  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter
    |       |
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-33941.stderr b/tests/ui/issues/issue-33941.current.stderr
index 9535ea57430..d653bbd3274 100644
--- a/tests/ui/issues/issue-33941.stderr
+++ b/tests/ui/issues/issue-33941.current.stderr
@@ -1,5 +1,5 @@
 error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
-  --> $DIR/issue-33941.rs:6:36
+  --> $DIR/issue-33941.rs:9:36
    |
 LL |     for _ in HashMap::new().iter().cloned() {}
    |                                    ^^^^^^ expected `&_`, found `(&_, &_)`
@@ -7,7 +7,7 @@ LL |     for _ in HashMap::new().iter().cloned() {}
    = note: expected reference `&_`
                   found tuple `(&_, &_)`
 note: the method call chain might not have had the expected associated types
-  --> $DIR/issue-33941.rs:6:29
+  --> $DIR/issue-33941.rs:9:29
    |
 LL |     for _ in HashMap::new().iter().cloned() {}
    |              -------------- ^^^^^^ `Iterator::Item` is `(&_, &_)` here
@@ -17,7 +17,7 @@ note: required by a bound in `cloned`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
 error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
-  --> $DIR/issue-33941.rs:6:14
+  --> $DIR/issue-33941.rs:9:14
    |
 LL |     for _ in HashMap::new().iter().cloned() {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&_`, found `(&_, &_)`
diff --git a/tests/ui/issues/issue-33941.next.stderr b/tests/ui/issues/issue-33941.next.stderr
new file mode 100644
index 00000000000..a5a6e51545a
--- /dev/null
+++ b/tests/ui/issues/issue-33941.next.stderr
@@ -0,0 +1,25 @@
+error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+  --> $DIR/issue-33941.rs:9:36
+   |
+LL |     for _ in HashMap::new().iter().cloned() {}
+   |                                    ^^^^^^ expected `&_`, found `(&_, &_)`
+   |
+   = note: expected reference `&_`
+                  found tuple `(&_, &_)`
+note: required by a bound in `cloned`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+
+error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+  --> $DIR/issue-33941.rs:9:14
+   |
+LL |     for _ in HashMap::new().iter().cloned() {}
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&_`, found `(&_, &_)`
+   |
+   = note: expected reference `&_`
+                  found tuple `(&_, &_)`
+   = note: required for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` to implement `Iterator`
+   = note: required for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` to implement `IntoIterator`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/issues/issue-33941.rs b/tests/ui/issues/issue-33941.rs
index 7b5be30834b..b0736204a08 100644
--- a/tests/ui/issues/issue-33941.rs
+++ b/tests/ui/issues/issue-33941.rs
@@ -1,8 +1,12 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
 //@ compile-flags: -Zdeduplicate-diagnostics=yes
 
 use std::collections::HashMap;
 
 fn main() {
-    for _ in HashMap::new().iter().cloned() {} //~ ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+    for _ in HashMap::new().iter().cloned() {}
     //~^ ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+    //~| ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
 }
diff --git a/tests/ui/issues/issue-50714-1.rs b/tests/ui/issues/issue-50714-1.rs
deleted file mode 100644
index a25940ce1cb..00000000000
--- a/tests/ui/issues/issue-50714-1.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-// Regression test for issue 50714, make sure that this isn't a linker error.
-
-#![no_std]
-#![feature(start)]
-
-extern crate std;
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize where fn(&()): Eq { //~ ERROR [E0647]
-    0
-}
diff --git a/tests/ui/issues/issue-50714-1.stderr b/tests/ui/issues/issue-50714-1.stderr
deleted file mode 100644
index 7593ac38346..00000000000
--- a/tests/ui/issues/issue-50714-1.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0647]: `#[start]` function is not allowed to have a `where` clause
-  --> $DIR/issue-50714-1.rs:9:50
-   |
-LL | fn start(_: isize, _: *const *const u8) -> isize where fn(&()): Eq {
-   |                                                  ^^^^^^^^^^^^^^^^^ `#[start]` function cannot have a `where` clause
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0647`.
diff --git a/tests/ui/issues/issue-50781.rs b/tests/ui/issues/issue-50781.rs
index 32253c3c236..ab90db1cadc 100644
--- a/tests/ui/issues/issue-50781.rs
+++ b/tests/ui/issues/issue-50781.rs
@@ -9,11 +9,11 @@ impl X for () {
 }
 
 impl Trait for dyn X {}
-//~^ ERROR the trait `X` cannot be made into an object
+//~^ ERROR the trait `X` is not dyn compatible
 
 pub fn main() {
     // Check that this does not segfault.
     <dyn X as X>::foo(&());
-    //~^ ERROR the trait `X` cannot be made into an object
-    //~| ERROR the trait `X` cannot be made into an object
+    //~^ ERROR the trait `X` is not dyn compatible
+    //~| ERROR the trait `X` is not dyn compatible
 }
diff --git a/tests/ui/issues/issue-50781.stderr b/tests/ui/issues/issue-50781.stderr
index 3e54a53aa95..293e9839944 100644
--- a/tests/ui/issues/issue-50781.stderr
+++ b/tests/ui/issues/issue-50781.stderr
@@ -1,51 +1,54 @@
-error[E0038]: the trait `X` cannot be made into an object
+error[E0038]: the trait `X` is not dyn compatible
   --> $DIR/issue-50781.rs:11:16
    |
 LL | impl Trait for dyn X {}
-   |                ^^^^^ `X` cannot be made into an object
+   |                ^^^^^ `X` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-50781.rs:4:8
    |
 LL | trait X {
-   |       - this trait cannot be made into an object...
+   |       - this trait is not dyn compatible...
 LL |     fn foo(&self) where Self: Trait;
    |        ^^^ ...because method `foo` references the `Self` type in its `where` clause
    = help: consider moving `foo` to another trait
-   = help: only type `()` implements the trait, consider using it directly instead
+   = help: only type `()` implements `X`; consider using it directly instead.
 
-error[E0038]: the trait `X` cannot be made into an object
+error[E0038]: the trait `X` is not dyn compatible
   --> $DIR/issue-50781.rs:16:23
    |
 LL |     <dyn X as X>::foo(&());
-   |                       ^^^ `X` cannot be made into an object
+   |                       ^^^ `X` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-50781.rs:4:8
    |
 LL | trait X {
-   |       - this trait cannot be made into an object...
+   |       - this trait is not dyn compatible...
 LL |     fn foo(&self) where Self: Trait;
    |        ^^^ ...because method `foo` references the `Self` type in its `where` clause
    = help: consider moving `foo` to another trait
-   = help: only type `()` implements the trait, consider using it directly instead
+   = help: only type `()` implements `X`; consider using it directly instead.
    = note: required for the cast from `&()` to `&dyn X`
 
-error[E0038]: the trait `X` cannot be made into an object
+error[E0038]: the trait `X` is not dyn compatible
   --> $DIR/issue-50781.rs:16:6
    |
 LL |     <dyn X as X>::foo(&());
-   |      ^^^^^ `X` cannot be made into an object
+   |      ^^^^^ `X` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-50781.rs:4:8
    |
 LL | trait X {
-   |       - this trait cannot be made into an object...
+   |       - this trait is not dyn compatible...
 LL |     fn foo(&self) where Self: Trait;
    |        ^^^ ...because method `foo` references the `Self` type in its `where` clause
    = help: consider moving `foo` to another trait
-   = help: only type `()` implements the trait, consider using it directly instead
+   = help: only type `()` implements `X`; consider using it directly instead.
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/issues/issue-9575.rs b/tests/ui/issues/issue-9575.rs
deleted file mode 100644
index 06b252990b6..00000000000
--- a/tests/ui/issues/issue-9575.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-#![feature(start)]
-
-#[start]
-fn start(argc: isize, argv: *const *const u8, crate_map: *const u8) -> isize {
-    //~^ `#[start]` function has wrong type
-   0
-}
diff --git a/tests/ui/issues/issue-9575.stderr b/tests/ui/issues/issue-9575.stderr
deleted file mode 100644
index 2f6e2687d24..00000000000
--- a/tests/ui/issues/issue-9575.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0308]: `#[start]` function has wrong type
-  --> $DIR/issue-9575.rs:4:1
-   |
-LL | fn start(argc: isize, argv: *const *const u8, crate_map: *const u8) -> isize {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
-   |
-   = note: expected signature `fn(isize, *const *const u8) -> _`
-              found signature `fn(isize, *const *const u8, *const u8) -> _`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr
index c392879db3e..83446fc9ec0 100644
--- a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr
+++ b/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr
@@ -19,33 +19,35 @@ note: required by a bound in `take_param`
 LL | fn take_param<T:Foo>(foo: &T) { }
    |                 ^^^ required by this bound in `take_param`
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/kindck-inherited-copy-bound.rs:28:19
    |
 LL |     let z = &x as &dyn Foo;
-   |                   ^^^^^^^^ `Foo` cannot be made into an object
+   |                   ^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/kindck-inherited-copy-bound.rs:10:13
    |
 LL | trait Foo : Copy {
    |       ---   ^^^^ ...because it requires `Self: Sized`
    |       |
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/kindck-inherited-copy-bound.rs:28:13
    |
 LL |     let z = &x as &dyn Foo;
-   |             ^^ `Foo` cannot be made into an object
+   |             ^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/kindck-inherited-copy-bound.rs:10:13
    |
 LL | trait Foo : Copy {
    |       ---   ^^^^ ...because it requires `Self: Sized`
    |       |
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
    = note: required for the cast from `&Box<{integer}>` to `&dyn Foo`
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr
index 34dcad13af3..271e5afb9e7 100644
--- a/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr
@@ -19,19 +19,20 @@ note: required by a bound in `take_param`
 LL | fn take_param<T:Foo>(foo: &T) { }
    |                 ^^^ required by this bound in `take_param`
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/kindck-inherited-copy-bound.rs:28:13
    |
 LL |     let z = &x as &dyn Foo;
-   |             ^^ `Foo` cannot be made into an object
+   |             ^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/kindck-inherited-copy-bound.rs:10:13
    |
 LL | trait Foo : Copy {
    |       ---   ^^^^ ...because it requires `Self: Sized`
    |       |
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
    = note: required for the cast from `&Box<i32>` to `&dyn Foo`
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/lang-items/issue-19660.rs b/tests/ui/lang-items/issue-19660.rs
deleted file mode 100644
index aff57df7ece..00000000000
--- a/tests/ui/lang-items/issue-19660.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-//@ error-pattern: requires `copy` lang_item
-
-#![feature(lang_items, start, no_core)]
-#![no_core]
-
-#[lang = "sized"]
-trait Sized { }
-
-struct S;
-
-#[start]
-fn main(_: isize, _: *const *const u8) -> isize {
-    let _ = S;
-    0
-}
diff --git a/tests/ui/lang-items/issue-19660.stderr b/tests/ui/lang-items/issue-19660.stderr
deleted file mode 100644
index e5a8a143d03..00000000000
--- a/tests/ui/lang-items/issue-19660.stderr
+++ /dev/null
@@ -1,4 +0,0 @@
-error: requires `copy` lang_item
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/lang-items/lang-item-missing.rs b/tests/ui/lang-items/lang-item-missing.rs
index 8762594202a..5b832a5bb8f 100644
--- a/tests/ui/lang-items/lang-item-missing.rs
+++ b/tests/ui/lang-items/lang-item-missing.rs
@@ -3,10 +3,11 @@
 
 //@ error-pattern: requires `sized` lang_item
 
-#![feature(start, no_core)]
+#![feature(lang_items, no_core)]
 #![no_core]
+#![no_main]
 
-#[start]
-fn start(argc: isize, argv: *const *const u8) -> isize {
-    0
+#[no_mangle]
+extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 {
+    loop {}
 }
diff --git a/tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs b/tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs
new file mode 100644
index 00000000000..9b634ee8ee3
--- /dev/null
+++ b/tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs
@@ -0,0 +1,15 @@
+//@ error-pattern: requires `copy` lang_item
+
+#![feature(lang_items, no_core)]
+#![no_core]
+#![no_main]
+
+#[lang = "sized"]
+trait Sized { }
+
+struct S;
+
+#[no_mangle]
+extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
+    argc
+}
diff --git a/tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr b/tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr
new file mode 100644
index 00000000000..3dc7716ecd2
--- /dev/null
+++ b/tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr
@@ -0,0 +1,8 @@
+error: requires `copy` lang_item
+  --> $DIR/missing-copy-lang-item-issue-19660.rs:14:5
+   |
+LL |     argc
+   |     ^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/layout/reprc-power-alignment.rs b/tests/ui/layout/reprc-power-alignment.rs
new file mode 100644
index 00000000000..f6c1df55988
--- /dev/null
+++ b/tests/ui/layout/reprc-power-alignment.rs
@@ -0,0 +1,152 @@
+//@ check-pass
+//@ compile-flags: --target powerpc64-ibm-aix
+//@ needs-llvm-components: powerpc
+//@ add-core-stubs
+#![feature(no_core)]
+#![no_core]
+#![no_std]
+
+extern crate minicore;
+use minicore::*;
+
+#[warn(uses_power_alignment)]
+
+#[repr(C)]
+pub struct Floats {
+    a: f64,
+    b: u8,
+    c: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+    d: f32,
+}
+
+pub struct Floats2 {
+    a: f64,
+    b: u32,
+    c: f64,
+}
+
+#[repr(C)]
+pub struct Floats3 {
+    a: f32,
+    b: f32,
+    c: i64,
+}
+
+#[repr(C)]
+pub struct Floats4 {
+    a: u64,
+    b: u32,
+    c: f32,
+}
+
+#[repr(C)]
+pub struct Floats5 {
+    a: f32,
+    b: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+    c: f32,
+}
+
+#[repr(C)]
+pub struct FloatAgg1 {
+    x: Floats,
+    y: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+}
+
+#[repr(C)]
+pub struct FloatAgg2 {
+    x: i64,
+    y: Floats, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+}
+
+#[repr(C)]
+pub struct FloatAgg3 {
+    x: FloatAgg1,
+    // NOTE: the "power" alignment rule is infectious to nested struct fields.
+    y: FloatAgg2, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+    z: FloatAgg2, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+}
+
+#[repr(C)]
+pub struct FloatAgg4 {
+    x: FloatAgg1,
+    y: FloatAgg2, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+}
+
+#[repr(C)]
+pub struct FloatAgg5 {
+    x: FloatAgg1,
+    y: FloatAgg2, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+    z: FloatAgg3, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+}
+
+#[repr(C)]
+pub struct FloatAgg6 {
+    x: i64,
+    y: Floats, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+    z: u8,
+}
+
+#[repr(C)]
+pub struct FloatAgg7 {
+    x: i64,
+    y: Floats, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+    z: u8,
+    zz: f32,
+}
+
+#[repr(C)]
+pub struct A {
+  d: f64,
+}
+#[repr(C)]
+pub struct B {
+  a: A,
+  f: f32,
+  d: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+}
+#[repr(C)]
+pub struct C {
+  c: u8,
+  b: B, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+}
+#[repr(C)]
+pub struct D {
+  x: f64,
+}
+#[repr(C)]
+pub struct E {
+  x: i32,
+  d: D, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+}
+#[repr(C)]
+pub struct F {
+  a: u8,
+  b: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+}
+#[repr(C)]
+pub struct G {
+    a: u8,
+    b: u8,
+    c: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+    d: f32,
+    e: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+}
+// Should not warn on #[repr(packed)].
+#[repr(packed)]
+pub struct H {
+    a: u8,
+    b: u8,
+    c: f64,
+    d: f32,
+    e: f64,
+}
+#[repr(C, packed)]
+pub struct I {
+    a: u8,
+    b: u8,
+    c: f64,
+    d: f32,
+    e: f64,
+}
+
+fn main() { }
diff --git a/tests/ui/layout/reprc-power-alignment.stderr b/tests/ui/layout/reprc-power-alignment.stderr
new file mode 100644
index 00000000000..18664e4d655
--- /dev/null
+++ b/tests/ui/layout/reprc-power-alignment.stderr
@@ -0,0 +1,112 @@
+warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+  --> $DIR/reprc-power-alignment.rs:18:5
+   |
+LL |     c: f64,
+   |     ^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/reprc-power-alignment.rs:12:8
+   |
+LL | #[warn(uses_power_alignment)]
+   |        ^^^^^^^^^^^^^^^^^^^^
+
+warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+  --> $DIR/reprc-power-alignment.rs:45:5
+   |
+LL |     b: f64,
+   |     ^^^^^^
+   |
+   = note: `#[warn(uses_power_alignment)]` on by default
+
+warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+  --> $DIR/reprc-power-alignment.rs:52:5
+   |
+LL |     y: f64,
+   |     ^^^^^^
+
+warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+  --> $DIR/reprc-power-alignment.rs:58:5
+   |
+LL |     y: Floats,
+   |     ^^^^^^^^^
+
+warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+  --> $DIR/reprc-power-alignment.rs:65:5
+   |
+LL |     y: FloatAgg2,
+   |     ^^^^^^^^^^^^
+
+warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+  --> $DIR/reprc-power-alignment.rs:66:5
+   |
+LL |     z: FloatAgg2,
+   |     ^^^^^^^^^^^^
+
+warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+  --> $DIR/reprc-power-alignment.rs:72:5
+   |
+LL |     y: FloatAgg2,
+   |     ^^^^^^^^^^^^
+
+warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+  --> $DIR/reprc-power-alignment.rs:78:5
+   |
+LL |     y: FloatAgg2,
+   |     ^^^^^^^^^^^^
+
+warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+  --> $DIR/reprc-power-alignment.rs:79:5
+   |
+LL |     z: FloatAgg3,
+   |     ^^^^^^^^^^^^
+
+warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+  --> $DIR/reprc-power-alignment.rs:85:5
+   |
+LL |     y: Floats,
+   |     ^^^^^^^^^
+
+warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+  --> $DIR/reprc-power-alignment.rs:92:5
+   |
+LL |     y: Floats,
+   |     ^^^^^^^^^
+
+warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+  --> $DIR/reprc-power-alignment.rs:105:3
+   |
+LL |   d: f64,
+   |   ^^^^^^
+
+warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+  --> $DIR/reprc-power-alignment.rs:110:3
+   |
+LL |   b: B,
+   |   ^^^^
+
+warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+  --> $DIR/reprc-power-alignment.rs:119:3
+   |
+LL |   d: D,
+   |   ^^^^
+
+warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+  --> $DIR/reprc-power-alignment.rs:124:3
+   |
+LL |   b: f64,
+   |   ^^^^^^
+
+warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+  --> $DIR/reprc-power-alignment.rs:130:5
+   |
+LL |     c: f64,
+   |     ^^^^^^
+
+warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
+  --> $DIR/reprc-power-alignment.rs:132:5
+   |
+LL |     e: f64,
+   |     ^^^^^^
+
+warning: 17 warnings emitted
+
diff --git a/tests/ui/layout/valid_range_oob.stderr b/tests/ui/layout/valid_range_oob.stderr
index 9c360b2cd6e..1a0c3841250 100644
--- a/tests/ui/layout/valid_range_oob.stderr
+++ b/tests/ui/layout/valid_range_oob.stderr
@@ -5,4 +5,4 @@ error: the compiler unexpectedly panicked. this is a bug.
 query stack during panic:
 #0 [layout_of] computing layout of `Foo`
 #1 [eval_to_allocation_raw] const-evaluating + checking `FOO`
-end of query stack
+... and 2 other queries... use `env RUST_BACKTRACE=1` to see the full query stack
diff --git a/tests/ui/lint/clashing-extern-fn.rs b/tests/ui/lint/clashing-extern-fn.rs
index a12fe81eecd..9bbb20246df 100644
--- a/tests/ui/lint/clashing-extern-fn.rs
+++ b/tests/ui/lint/clashing-extern-fn.rs
@@ -248,6 +248,7 @@ mod sameish_members {
 
 mod same_sized_members_clash {
     mod a {
+        #[allow(uses_power_alignment)]
         #[repr(C)]
         struct Point3 {
             x: f32,
diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr
index b30dd476a1d..48dd1adbc1f 100644
--- a/tests/ui/lint/clashing-extern-fn.stderr
+++ b/tests/ui/lint/clashing-extern-fn.stderr
@@ -1,5 +1,5 @@
 warning: `extern` block uses type `Option<TransparentNoNiche>`, which is not FFI-safe
-  --> $DIR/clashing-extern-fn.rs:482:55
+  --> $DIR/clashing-extern-fn.rs:483:55
    |
 LL |             fn hidden_niche_transparent_no_niche() -> Option<TransparentNoNiche>;
    |                                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -9,7 +9,7 @@ LL |             fn hidden_niche_transparent_no_niche() -> Option<TransparentNoN
    = note: `#[warn(improper_ctypes)]` on by default
 
 warning: `extern` block uses type `Option<UnsafeCell<NonZero<usize>>>`, which is not FFI-safe
-  --> $DIR/clashing-extern-fn.rs:486:46
+  --> $DIR/clashing-extern-fn.rs:487:46
    |
 LL |             fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZero<usize>>>;
    |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -151,7 +151,7 @@ LL |             fn draw_point(p: Point);
               found `unsafe extern "C" fn(sameish_members::b::Point)`
 
 warning: `origin` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:269:13
+  --> $DIR/clashing-extern-fn.rs:270:13
    |
 LL |             fn origin() -> Point3;
    |             ---------------------- `origin` previously declared here
@@ -163,7 +163,7 @@ LL |             fn origin() -> Point3;
               found `unsafe extern "C" fn() -> same_sized_members_clash::b::Point3`
 
 warning: `transparent_incorrect` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:292:13
+  --> $DIR/clashing-extern-fn.rs:293:13
    |
 LL |             fn transparent_incorrect() -> T;
    |             -------------------------------- `transparent_incorrect` previously declared here
@@ -175,7 +175,7 @@ LL |             fn transparent_incorrect() -> isize;
               found `unsafe extern "C" fn() -> isize`
 
 warning: `missing_return_type` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:310:13
+  --> $DIR/clashing-extern-fn.rs:311:13
    |
 LL |             fn missing_return_type() -> usize;
    |             ---------------------------------- `missing_return_type` previously declared here
@@ -187,7 +187,7 @@ LL |             fn missing_return_type();
               found `unsafe extern "C" fn()`
 
 warning: `non_zero_usize` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:328:13
+  --> $DIR/clashing-extern-fn.rs:329:13
    |
 LL |             fn non_zero_usize() -> core::num::NonZero<usize>;
    |             ------------------------------------------------- `non_zero_usize` previously declared here
@@ -199,7 +199,7 @@ LL |             fn non_zero_usize() -> usize;
               found `unsafe extern "C" fn() -> usize`
 
 warning: `non_null_ptr` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:330:13
+  --> $DIR/clashing-extern-fn.rs:331:13
    |
 LL |             fn non_null_ptr() -> core::ptr::NonNull<usize>;
    |             ----------------------------------------------- `non_null_ptr` previously declared here
@@ -211,7 +211,7 @@ LL |             fn non_null_ptr() -> *const usize;
               found `unsafe extern "C" fn() -> *const usize`
 
 warning: `option_non_zero_usize_incorrect` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:424:13
+  --> $DIR/clashing-extern-fn.rs:425:13
    |
 LL |             fn option_non_zero_usize_incorrect() -> usize;
    |             ---------------------------------------------- `option_non_zero_usize_incorrect` previously declared here
@@ -223,7 +223,7 @@ LL |             fn option_non_zero_usize_incorrect() -> isize;
               found `unsafe extern "C" fn() -> isize`
 
 warning: `option_non_null_ptr_incorrect` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:426:13
+  --> $DIR/clashing-extern-fn.rs:427:13
    |
 LL |             fn option_non_null_ptr_incorrect() -> *const usize;
    |             --------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here
@@ -235,7 +235,7 @@ LL |             fn option_non_null_ptr_incorrect() -> *const isize;
               found `unsafe extern "C" fn() -> *const isize`
 
 warning: `hidden_niche_transparent_no_niche` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:482:13
+  --> $DIR/clashing-extern-fn.rs:483:13
    |
 LL |             fn hidden_niche_transparent_no_niche() -> usize;
    |             ------------------------------------------------ `hidden_niche_transparent_no_niche` previously declared here
@@ -247,7 +247,7 @@ LL |             fn hidden_niche_transparent_no_niche() -> Option<TransparentNoN
               found `unsafe extern "C" fn() -> Option<TransparentNoNiche>`
 
 warning: `hidden_niche_unsafe_cell` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:486:13
+  --> $DIR/clashing-extern-fn.rs:487:13
    |
 LL |             fn hidden_niche_unsafe_cell() -> usize;
    |             --------------------------------------- `hidden_niche_unsafe_cell` previously declared here
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr
index fd434eacf3d..e1c12cfd1a5 100644
--- a/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr
@@ -7,6 +7,8 @@ LL |         dbg!(String::new().as_ptr());
    |              this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 note: the lint level is defined here
   --> $DIR/allow.rs:7:12
@@ -23,6 +25,8 @@ LL |         dbg!(String::new().as_ptr());
    |              this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 note: the lint level is defined here
   --> $DIR/allow.rs:18:12
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr
index d1615b76d82..41c6cdd0e3e 100644
--- a/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr
@@ -7,6 +7,8 @@ LL |         let ptr = cstring().as_ptr();
    |                   this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 note: the lint level is defined here
   --> $DIR/calls.rs:1:9
@@ -23,6 +25,8 @@ LL |         let ptr = cstring().as_ptr();
    |                   this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `CString` will be dropped
@@ -34,6 +38,8 @@ LL |     let _ptr: *const u8 = cstring().as_ptr().cast();
    |                           this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `CString` will be dropped
@@ -45,6 +51,8 @@ LL |     let _ptr: *const u8 = { cstring() }.as_ptr().cast();
    |                           this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `CString` will be dropped
@@ -56,6 +64,8 @@ LL |     let _ptr: *const u8 = { cstring().as_ptr() }.cast();
    |                             this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: aborting due to 5 previous errors
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr
index 5289fbb8723..d4126ba231f 100644
--- a/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr
@@ -15,6 +15,8 @@ LL |     let s = CString::new("some text").unwrap().as_ptr();
    |             this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 note: the lint level is defined here
   --> $DIR/cstring-as-ptr.rs:2:9
@@ -34,6 +36,8 @@ LL |     mymacro!();
    |     ---------- in this macro invocation
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
    = note: this error originates in the macro `mymacro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr
index 0de794f6ae2..aace55e92cf 100644
--- a/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr
@@ -7,6 +7,8 @@ LL |     let str1 = String::with_capacity(MAX_PATH).as_mut_ptr();
    |                this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_mut_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_mut_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 note: the lint level is defined here
   --> $DIR/example-from-issue123613.rs:1:9
@@ -23,6 +25,8 @@ LL |     let str2 = String::from("TotototototototototototototototototoT").as_ptr
    |                this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr
index 5d401c89c0c..976334ddef9 100644
--- a/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr
@@ -7,6 +7,8 @@ LL |     let _ptr1 = Vec::<u32>::new().as_ptr().dbg();
    |                 this `Vec<u32>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u32>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `Vec<u32>` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `Vec<u32>` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 note: the lint level is defined here
   --> $DIR/ext.rs:1:9
@@ -23,6 +25,8 @@ LL |     let _ptr2 = vec![0].as_ptr().foo();
    |                 this `Vec<u32>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u32>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `Vec<u32>` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `Vec<u32>` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr
index 11c052c158e..a86a69bc39a 100644
--- a/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr
@@ -7,6 +7,8 @@ LL |     vec![0u8].as_ptr();
    |     this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `Vec<u8>` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `Vec<u8>` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 note: the lint level is defined here
   --> $DIR/methods.rs:1:9
@@ -23,6 +25,8 @@ LL |     vec![0u8].as_mut_ptr();
    |     this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_mut_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `Vec<u8>` to lives at least as long as the pointer returned by the call to `as_mut_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `Vec<u8>` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr
index d2e9ac8c4e9..e8994703cab 100644
--- a/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr
@@ -7,6 +7,8 @@ LL |     string().as_ptr();
    |     this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 note: the lint level is defined here
   --> $DIR/temporaries.rs:2:9
@@ -23,6 +25,8 @@ LL |     "hello".to_string().as_ptr();
    |     this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `String` will be dropped
@@ -34,6 +38,8 @@ LL |     (string() + "hello").as_ptr();
    |     this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `String` will be dropped
@@ -45,6 +51,8 @@ LL |         (if true { String::new() } else { "hello".into() }).as_ptr();
    |         this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `String` will be dropped
@@ -58,6 +66,8 @@ LL |           .as_ptr();
    |            ^^^^^^ this pointer will immediately be invalid
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `String` will be dropped
@@ -71,6 +81,8 @@ LL |           .as_ptr();
    |            ^^^^^^ this pointer will immediately be invalid
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `String` will be dropped
@@ -82,6 +94,8 @@ LL |     { string() }.as_ptr();
    |     this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
@@ -93,6 +107,8 @@ LL |     vec![0u8].as_ptr();
    |     this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `Vec<u8>` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `Vec<u8>` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: aborting due to 8 previous errors
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr
index 250ed6dc9e3..fab2459b53f 100644
--- a/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr
@@ -7,6 +7,8 @@ LL |     declval::<CString>().as_ptr();
    |     this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 note: the lint level is defined here
   --> $DIR/types.rs:1:9
@@ -23,6 +25,8 @@ LL |     declval::<String>().as_ptr();
    |     this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
@@ -34,6 +38,8 @@ LL |     declval::<Vec<u8>>().as_ptr();
    |     this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `Vec<u8>` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `Vec<u8>` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<CString>` will be dropped
@@ -45,6 +51,8 @@ LL |     declval::<Box<CString>>().as_ptr();
    |     this `Box<CString>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<CString>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `Box<CString>` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `Box<CString>` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped
@@ -56,6 +64,8 @@ LL |     declval::<Box<[u8]>>().as_ptr();
    |     this `Box<[u8]>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<[u8]>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `Box<[u8]>` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `Box<[u8]>` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<str>` will be dropped
@@ -67,6 +77,8 @@ LL |     declval::<Box<str>>().as_ptr();
    |     this `Box<str>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<str>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `Box<str>` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `Box<str>` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<CStr>` will be dropped
@@ -78,6 +90,8 @@ LL |     declval::<Box<CStr>>().as_ptr();
    |     this `Box<CStr>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<CStr>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `Box<CStr>` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `Box<CStr>` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped
@@ -89,6 +103,8 @@ LL |     declval::<[u8; 10]>().as_ptr();
    |     this `[u8; 10]` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `[u8; 10]` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `[u8; 10]` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `[u8; 10]` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped
@@ -100,6 +116,8 @@ LL |     declval::<Box<[u8; 10]>>().as_ptr();
    |     this `Box<[u8; 10]>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<[u8; 10]>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `Box<[u8; 10]>` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `Box<[u8; 10]>` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<Vec<u8>>` will be dropped
@@ -111,6 +129,8 @@ LL |     declval::<Box<Vec<u8>>>().as_ptr();
    |     this `Box<Vec<u8>>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<Vec<u8>>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `Box<Vec<u8>>` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `Box<Vec<u8>>` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<String>` will be dropped
@@ -122,6 +142,8 @@ LL |     declval::<Box<String>>().as_ptr();
    |     this `Box<String>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<String>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `Box<String>` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `Box<String>` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<Box<Box<Box<[u8]>>>>` will be dropped
@@ -133,6 +155,8 @@ LL |     declval::<Box<Box<Box<Box<[u8]>>>>>().as_ptr();
    |     this `Box<Box<Box<Box<[u8]>>>>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<Box<Box<Box<[u8]>>>>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `Box<Box<Box<Box<[u8]>>>>` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `Box<Box<Box<Box<[u8]>>>>` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Cell<u8>` will be dropped
@@ -144,6 +168,8 @@ LL |     declval::<Cell<u8>>().as_ptr();
    |     this `Cell<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `Cell<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `Cell<u8>` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `Cell<u8>` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `MaybeUninit<u8>` will be dropped
@@ -155,6 +181,8 @@ LL |     declval::<MaybeUninit<u8>>().as_ptr();
    |     this `MaybeUninit<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `MaybeUninit<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `MaybeUninit<u8>` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `MaybeUninit<u8>` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Vec<AsPtrFake>` will be dropped
@@ -166,6 +194,8 @@ LL |     declval::<Vec<AsPtrFake>>().as_ptr();
    |     this `Vec<AsPtrFake>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<AsPtrFake>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `Vec<AsPtrFake>` to lives at least as long as the pointer returned by the call to `as_ptr`
+   = help: in particular, if this pointer is returned from the current function, binding the `Vec<AsPtrFake>` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `UnsafeCell<u8>` will be dropped
@@ -177,6 +207,8 @@ LL |     declval::<UnsafeCell<u8>>().get();
    |     this `UnsafeCell<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `get` the `UnsafeCell<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `UnsafeCell<u8>` to lives at least as long as the pointer returned by the call to `get`
+   = help: in particular, if this pointer is returned from the current function, binding the `UnsafeCell<u8>` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `SyncUnsafeCell<u8>` will be dropped
@@ -188,6 +220,8 @@ LL |     declval::<SyncUnsafeCell<u8>>().get();
    |     this `SyncUnsafeCell<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `get` the `SyncUnsafeCell<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: you must make sure that the variable you bind the `SyncUnsafeCell<u8>` to lives at least as long as the pointer returned by the call to `get`
+   = help: in particular, if this pointer is returned from the current function, binding the `SyncUnsafeCell<u8>` inside the function will not suffice
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: aborting due to 17 previous errors
diff --git a/tests/ui/lint/dead-code/lint-dead-code-2.rs b/tests/ui/lint/dead-code/lint-dead-code-2.rs
index 6bfa4d96f71..c82088ec54b 100644
--- a/tests/ui/lint/dead-code/lint-dead-code-2.rs
+++ b/tests/ui/lint/dead-code/lint-dead-code-2.rs
@@ -1,6 +1,6 @@
 #![allow(unused_variables)]
 #![deny(dead_code)]
-#![feature(rustc_attrs, start)]
+#![feature(rustc_attrs)]
 
 struct Foo;
 
@@ -21,21 +21,16 @@ fn live_fn() {}
 
 fn dead_fn() {} //~ ERROR: function `dead_fn` is never used
 
-#[rustc_main]
-fn dead_fn2() {} //~ ERROR: function `dead_fn2` is never used
-
 fn used_fn() {}
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[rustc_main]
+fn actual_main() {
     used_fn();
     let foo = Foo;
     foo.bar2();
-    0
 }
 
 // this is not main
 fn main() { //~ ERROR: function `main` is never used
     dead_fn();
-    dead_fn2();
 }
diff --git a/tests/ui/lint/dead-code/lint-dead-code-2.stderr b/tests/ui/lint/dead-code/lint-dead-code-2.stderr
index 85af553c986..4a5f3b8a687 100644
--- a/tests/ui/lint/dead-code/lint-dead-code-2.stderr
+++ b/tests/ui/lint/dead-code/lint-dead-code-2.stderr
@@ -10,17 +10,11 @@ note: the lint level is defined here
 LL | #![deny(dead_code)]
    |         ^^^^^^^^^
 
-error: function `dead_fn2` is never used
-  --> $DIR/lint-dead-code-2.rs:25:4
-   |
-LL | fn dead_fn2() {}
-   |    ^^^^^^^^
-
 error: function `main` is never used
-  --> $DIR/lint-dead-code-2.rs:38:4
+  --> $DIR/lint-dead-code-2.rs:34:4
    |
 LL | fn main() {
    |    ^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/lint/wide_pointer_comparisons.stderr b/tests/ui/lint/wide_pointer_comparisons.stderr
index 7fe382393d7..78548e308ed 100644
--- a/tests/ui/lint/wide_pointer_comparisons.stderr
+++ b/tests/ui/lint/wide_pointer_comparisons.stderr
@@ -615,7 +615,7 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi
   --> $DIR/wide_pointer_comparisons.rs:169:37
    |
 LL |             ($a:expr, $b:expr) => { $a == $b }
-   |                                     ^^
+   |                                     ^^^^^^^^
 ...
 LL |         cmp!(&a, &b);
    |         ------------ in this macro invocation
diff --git a/tests/ui/macros/not-utf8.rs b/tests/ui/macros/not-utf8.rs
index 8100d65a9f8..ad8ac39d230 100644
--- a/tests/ui/macros/not-utf8.rs
+++ b/tests/ui/macros/not-utf8.rs
@@ -3,5 +3,5 @@
 //@ reference: input.encoding.invalid
 
 fn foo() {
-    include!("not-utf8.bin")
+    include!("not-utf8.bin");
 }
diff --git a/tests/ui/macros/not-utf8.stderr b/tests/ui/macros/not-utf8.stderr
index 0d587cab5f3..17ee8197ac8 100644
--- a/tests/ui/macros/not-utf8.stderr
+++ b/tests/ui/macros/not-utf8.stderr
@@ -1,9 +1,14 @@
-error: couldn't read $DIR/not-utf8.bin: stream did not contain valid UTF-8
+error: couldn't read `$DIR/not-utf8.bin`: stream did not contain valid UTF-8
   --> $DIR/not-utf8.rs:6:5
    |
-LL |     include!("not-utf8.bin")
+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�␝�:�...
+   | ^
    = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs
index 37d94830db2..2a27164f9cb 100644
--- a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs
+++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs
@@ -1,4 +1,6 @@
-//@ compile-flags: --test
+// -Zpanic_abort_tests makes this test work on panic=abort targets and
+// it's a no-op on panic=unwind targets
+//@ compile-flags: --test -Zpanic_abort_tests
 //@ run-pass
 
 #![feature(core_intrinsics, generic_assert)]
diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs
index 86cc7adb90d..254d59076e5 100644
--- a/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs
+++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs
@@ -1,4 +1,6 @@
-//@ compile-flags: --test
+// -Zpanic_abort_tests makes this test work on panic=abort targets and
+// it's a no-op on panic=unwind targets
+//@ compile-flags: --test -Zpanic_abort_tests
 // ignore-tidy-linelength
 //@ run-pass
 
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.both.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.both.stderr
deleted file mode 100644
index f8672d755b9..00000000000
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.both.stderr
+++ /dev/null
@@ -1,169 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:8:17
-   |
-LL |     if let Some(&mut Some(&_)) = &Some(&Some(0)) {
-   |                 ^^^^^^^^^^^^^    --------------- this expression has type `&Option<&Option<{integer}>>`
-   |                 |
-   |                 types differ in mutability
-   |
-   = note:      expected reference `&Option<{integer}>`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:11:23
-   |
-LL |     if let Some(&Some(&mut _)) = &Some(&mut Some(0)) {
-   |                       ^^^^^^     ------------------- this expression has type `&Option<&mut Option<{integer}>>`
-   |                       |
-   |                       expected integer, found `&mut _`
-   |
-   = note:           expected type `{integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:15:27
-   |
-LL |         let _: &mut u32 = x;
-   |                --------   ^ types differ in mutability
-   |                |
-   |                expected due to this
-   |
-   = note: expected mutable reference `&mut u32`
-                      found reference `&{integer}`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:18:23
-   |
-LL |     if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
-   |                       ^^^^^^     ------------------- this expression has type `&mut Option<&Option<{integer}>>`
-   |                       |
-   |                       expected integer, found `&mut _`
-   |
-   = note:           expected type `{integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:21:29
-   |
-LL |     if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
-   |                             ^^^^^^       ------------------------- this expression has type `&Option<Option<&mut Option<{integer}>>>`
-   |                             |
-   |                             expected integer, found `&mut _`
-   |
-   = note:           expected type `{integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:24:17
-   |
-LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
-   |                 ^^^^^^^^^^^^    -------------- this expression has type `&Option<Option<{integer}>>`
-   |                 |
-   |                 expected `Option<{integer}>`, found `&mut _`
-   |
-   = note:           expected enum `Option<{integer}>`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:27:17
-   |
-LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
-   |                 ^^^^^^^^^^^^    -------------- this expression has type `&Option<Option<{integer}>>`
-   |                 |
-   |                 expected `Option<{integer}>`, found `&mut _`
-   |
-   = note:           expected enum `Option<{integer}>`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:31:9
-   |
-LL |     let &mut _ = &&0;
-   |         ^^^^^^   --- this expression has type `&&{integer}`
-   |         |
-   |         types differ in mutability
-   |
-   = note:      expected reference `&&{integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:34:9
-   |
-LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
-   |         ^^^^^^   ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
-   |         |
-   |         types differ in mutability
-   |
-   = note:      expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:45:9
-   |
-LL |     let &mut _ = &&mut 0;
-   |         ^^^^^^   ------- this expression has type `&&mut {integer}`
-   |         |
-   |         types differ in mutability
-   |
-   = note:      expected reference `&&mut {integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:48:9
-   |
-LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0;
-   |         ^^^^^^   --------------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}`
-   |         |
-   |         types differ in mutability
-   |
-   = note:      expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:51:14
-   |
-LL |     let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0;
-   |              ^^^^^^^^^^^^^^^^   -------------------------- this expression has type `&mut &&&&mut &&&mut &mut {integer}`
-   |              |
-   |              types differ in mutability
-   |
-   = note:      expected reference `&&&&mut &&&mut &mut {integer}`
-           found mutable reference `&mut _`
-
-error[E0658]: binding cannot be both mutable and by-reference
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:60:13
-   |
-LL |     let Foo(mut a) = &Foo(0);
-   |             ^^^^
-   |
-   = note: see issue #123076 <https://github.com/rust-lang/rust/issues/123076> for more information
-   = help: add `#![feature(mut_ref)]` 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]: binding cannot be both mutable and by-reference
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:64:13
-   |
-LL |     let Foo(mut a) = &mut Foo(0);
-   |             ^^^^
-   |
-   = note: see issue #123076 <https://github.com/rust-lang/rust/issues/123076> for more information
-   = help: add `#![feature(mut_ref)]` 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[E0277]: the trait bound `&_: main::Ref` is not satisfied
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:82:14
-   |
-LL |     let &_ = generic();
-   |              ^^^^^^^^^ the trait `main::Ref` is not implemented for `&_`
-   |
-   = help: the trait `main::Ref` is implemented for `&'static mut [(); 0]`
-note: required by a bound in `generic`
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:68:19
-   |
-LL |     fn generic<R: Ref>() -> R {
-   |                   ^^^ required by this bound in `generic`
-
-error: aborting due to 15 previous errors
-
-Some errors have detailed explanations: E0277, E0308, E0658.
-For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.classic.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.classic.stderr
deleted file mode 100644
index a37316b3097..00000000000
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.classic.stderr
+++ /dev/null
@@ -1,199 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:8:17
-   |
-LL |     if let Some(&mut Some(&_)) = &Some(&Some(0)) {
-   |                 ^^^^^
-   |
-   = note: cannot match inherited `&` with `&mut` pattern
-help: replace this `&mut` pattern with `&`
-   |
-LL |     if let Some(&Some(&_)) = &Some(&Some(0)) {
-   |                 ~
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:11:23
-   |
-LL |     if let Some(&Some(&mut _)) = &Some(&mut Some(0)) {
-   |                       ^^^^^
-   |
-   = note: cannot match inherited `&` with `&mut` pattern
-help: replace this `&mut` pattern with `&`
-   |
-LL |     if let Some(&Some(&_)) = &Some(&mut Some(0)) {
-   |                       ~
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:15:27
-   |
-LL |         let _: &mut u32 = x;
-   |                --------   ^ types differ in mutability
-   |                |
-   |                expected due to this
-   |
-   = note: expected mutable reference `&mut u32`
-                      found reference `&{integer}`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:18:23
-   |
-LL |     if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
-   |                       ^^^^^
-   |
-   = note: cannot match inherited `&` with `&mut` pattern
-help: replace this `&mut` pattern with `&`
-   |
-LL |     if let Some(&Some(&_)) = &mut Some(&Some(0)) {
-   |                       ~
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:21:29
-   |
-LL |     if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
-   |                             ^^^^^
-   |
-   = note: cannot match inherited `&` with `&mut` pattern
-help: replace this `&mut` pattern with `&`
-   |
-LL |     if let Some(&Some(Some((&_)))) = &Some(Some(&mut Some(0))) {
-   |                             ~
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:24:17
-   |
-LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
-   |                 ^^^^^
-   |
-   = note: cannot match inherited `&` with `&mut` pattern
-help: replace this `&mut` pattern with `&`
-   |
-LL |     if let Some(&Some(x)) = &Some(Some(0)) {
-   |                 ~
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:27:17
-   |
-LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
-   |                 ^^^^^
-   |
-   = note: cannot match inherited `&` with `&mut` pattern
-help: replace this `&mut` pattern with `&`
-   |
-LL |     if let Some(&Some(x)) = &Some(Some(0)) {
-   |                 ~
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:31:9
-   |
-LL |     let &mut _ = &&0;
-   |         ^^^^^^   --- this expression has type `&&{integer}`
-   |         |
-   |         types differ in mutability
-   |
-   = note:      expected reference `&&{integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:34:9
-   |
-LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
-   |         ^^^^^^   ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
-   |         |
-   |         types differ in mutability
-   |
-   = note:      expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:37:17
-   |
-LL |     if let Some(&mut Some(&_)) = &Some(&mut Some(0)) {
-   |                 ^^^^^
-   |
-   = note: cannot match inherited `&` with `&mut` pattern
-help: replace this `&mut` pattern with `&`
-   |
-LL |     if let Some(&Some(&_)) = &Some(&mut Some(0)) {
-   |                 ~
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:41:22
-   |
-LL |     if let Some(Some(&mut x)) = &Some(Some(&mut 0)) {
-   |                      ^^^^^
-   |
-   = note: cannot match inherited `&` with `&mut` pattern
-help: replace this `&mut` pattern with `&`
-   |
-LL |     if let Some(Some(&x)) = &Some(Some(&mut 0)) {
-   |                      ~
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:45:9
-   |
-LL |     let &mut _ = &&mut 0;
-   |         ^^^^^^   ------- this expression has type `&&mut {integer}`
-   |         |
-   |         types differ in mutability
-   |
-   = note:      expected reference `&&mut {integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:48:9
-   |
-LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0;
-   |         ^^^^^^   --------------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}`
-   |         |
-   |         types differ in mutability
-   |
-   = note:      expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:51:14
-   |
-LL |     let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0;
-   |              ^^^^^^^^^^^^^^^^   -------------------------- this expression has type `&mut &&&&mut &&&mut &mut {integer}`
-   |              |
-   |              types differ in mutability
-   |
-   = note:      expected reference `&&&&mut &&&mut &mut {integer}`
-           found mutable reference `&mut _`
-
-error[E0658]: binding cannot be both mutable and by-reference
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:60:13
-   |
-LL |     let Foo(mut a) = &Foo(0);
-   |             ^^^^
-   |
-   = note: see issue #123076 <https://github.com/rust-lang/rust/issues/123076> for more information
-   = help: add `#![feature(mut_ref)]` 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]: binding cannot be both mutable and by-reference
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:64:13
-   |
-LL |     let Foo(mut a) = &mut Foo(0);
-   |             ^^^^
-   |
-   = note: see issue #123076 <https://github.com/rust-lang/rust/issues/123076> for more information
-   = help: add `#![feature(mut_ref)]` 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[E0277]: the trait bound `&_: main::Ref` is not satisfied
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:82:14
-   |
-LL |     let &_ = generic();
-   |              ^^^^^^^^^ the trait `main::Ref` is not implemented for `&_`
-   |
-   = help: the trait `main::Ref` is implemented for `&'static mut [(); 0]`
-note: required by a bound in `generic`
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:68:19
-   |
-LL |     fn generic<R: Ref>() -> R {
-   |                   ^^^ required by this bound in `generic`
-
-error: aborting due to 17 previous errors
-
-Some errors have detailed explanations: E0277, E0308, E0658.
-For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs
deleted file mode 100644
index fd616807b28..00000000000
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs
+++ /dev/null
@@ -1,83 +0,0 @@
-//@ edition: 2024
-//@ revisions: classic structural both
-#![allow(incomplete_features)]
-#![cfg_attr(any(classic, both), feature(ref_pat_eat_one_layer_2024))]
-#![cfg_attr(any(structural, both), feature(ref_pat_eat_one_layer_2024_structural))]
-
-pub fn main() {
-    if let Some(&mut Some(&_)) = &Some(&Some(0)) {
-        //~^ ERROR: mismatched types
-    }
-    if let Some(&Some(&mut _)) = &Some(&mut Some(0)) {
-        //~^ ERROR: mismatched types
-    }
-    if let Some(&Some(x)) = &mut Some(&Some(0)) {
-        let _: &mut u32 = x;
-        //~^ ERROR: mismatched types
-    }
-    if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
-        //~^ ERROR: mismatched types
-    }
-    if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
-        //~^ ERROR: mismatched types
-    }
-    if let Some(&mut Some(x)) = &Some(Some(0)) {
-        //~^ ERROR: mismatched types
-    }
-    if let Some(&mut Some(x)) = &Some(Some(0)) {
-        //~^ ERROR: mismatched types
-    }
-
-    let &mut _ = &&0;
-    //~^ ERROR: mismatched types
-
-    let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
-    //~^ ERROR: mismatched types
-
-    if let Some(&mut Some(&_)) = &Some(&mut Some(0)) {
-        //[classic]~^ ERROR: mismatched types
-    }
-
-    if let Some(Some(&mut x)) = &Some(Some(&mut 0)) {
-        //[classic]~^ ERROR: mismatched types
-    }
-
-    let &mut _ = &&mut 0;
-    //~^ ERROR: mismatched types
-
-    let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0;
-    //~^ ERROR: mismatched types
-
-    let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0;
-    //~^ ERROR: mismatched types
-
-    if let Some(&mut _) = &mut Some(&0) {
-        //[structural]~^ ERROR
-    }
-
-    struct Foo(u8);
-
-    let Foo(mut a) = &Foo(0);
-    //~^ ERROR: binding cannot be both mutable and by-reference
-    a = &42;
-
-    let Foo(mut a) = &mut Foo(0);
-    //~^ ERROR: binding cannot be both mutable and by-reference
-    a = &mut 42;
-
-    fn generic<R: Ref>() -> R {
-        R::meow()
-    }
-
-    trait Ref: Sized {
-        fn meow() -> Self;
-    }
-
-    impl Ref for &'static mut [(); 0] {
-        fn meow() -> Self {
-            &mut []
-        }
-    }
-
-    let &_ = generic(); //~ERROR: the trait bound `&_: main::Ref` is not satisfied [E0277]
-}
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.structural.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.structural.stderr
deleted file mode 100644
index 2f62e9974fa..00000000000
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.structural.stderr
+++ /dev/null
@@ -1,180 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:8:17
-   |
-LL |     if let Some(&mut Some(&_)) = &Some(&Some(0)) {
-   |                 ^^^^^^^^^^^^^    --------------- this expression has type `&Option<&Option<{integer}>>`
-   |                 |
-   |                 types differ in mutability
-   |
-   = note:      expected reference `&Option<{integer}>`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:11:23
-   |
-LL |     if let Some(&Some(&mut _)) = &Some(&mut Some(0)) {
-   |                       ^^^^^^     ------------------- this expression has type `&Option<&mut Option<{integer}>>`
-   |                       |
-   |                       expected integer, found `&mut _`
-   |
-   = note:           expected type `{integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:15:27
-   |
-LL |         let _: &mut u32 = x;
-   |                --------   ^ types differ in mutability
-   |                |
-   |                expected due to this
-   |
-   = note: expected mutable reference `&mut u32`
-                      found reference `&{integer}`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:18:23
-   |
-LL |     if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
-   |                       ^^^^^^     ------------------- this expression has type `&mut Option<&Option<{integer}>>`
-   |                       |
-   |                       expected integer, found `&mut _`
-   |
-   = note:           expected type `{integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:21:29
-   |
-LL |     if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
-   |                             ^^^^^^       ------------------------- this expression has type `&Option<Option<&mut Option<{integer}>>>`
-   |                             |
-   |                             expected integer, found `&mut _`
-   |
-   = note:           expected type `{integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:24:17
-   |
-LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
-   |                 ^^^^^^^^^^^^    -------------- this expression has type `&Option<Option<{integer}>>`
-   |                 |
-   |                 expected `Option<{integer}>`, found `&mut _`
-   |
-   = note:           expected enum `Option<{integer}>`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:27:17
-   |
-LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
-   |                 ^^^^^^^^^^^^    -------------- this expression has type `&Option<Option<{integer}>>`
-   |                 |
-   |                 expected `Option<{integer}>`, found `&mut _`
-   |
-   = note:           expected enum `Option<{integer}>`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:31:9
-   |
-LL |     let &mut _ = &&0;
-   |         ^^^^^^   --- this expression has type `&&{integer}`
-   |         |
-   |         types differ in mutability
-   |
-   = note:      expected reference `&&{integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:34:9
-   |
-LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
-   |         ^^^^^^   ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
-   |         |
-   |         types differ in mutability
-   |
-   = note:      expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:45:9
-   |
-LL |     let &mut _ = &&mut 0;
-   |         ^^^^^^   ------- this expression has type `&&mut {integer}`
-   |         |
-   |         types differ in mutability
-   |
-   = note:      expected reference `&&mut {integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:48:9
-   |
-LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0;
-   |         ^^^^^^   --------------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}`
-   |         |
-   |         types differ in mutability
-   |
-   = note:      expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:51:14
-   |
-LL |     let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0;
-   |              ^^^^^^^^^^^^^^^^   -------------------------- this expression has type `&mut &&&&mut &&&mut &mut {integer}`
-   |              |
-   |              types differ in mutability
-   |
-   = note:      expected reference `&&&&mut &&&mut &mut {integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:54:17
-   |
-LL |     if let Some(&mut _) = &mut Some(&0) {
-   |                 ^^^^^^    ------------- this expression has type `&mut Option<&{integer}>`
-   |                 |
-   |                 types differ in mutability
-   |
-   = note:      expected reference `&{integer}`
-           found mutable reference `&mut _`
-
-error[E0658]: binding cannot be both mutable and by-reference
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:60:13
-   |
-LL |     let Foo(mut a) = &Foo(0);
-   |             ^^^^
-   |
-   = note: see issue #123076 <https://github.com/rust-lang/rust/issues/123076> for more information
-   = help: add `#![feature(mut_ref)]` 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]: binding cannot be both mutable and by-reference
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:64:13
-   |
-LL |     let Foo(mut a) = &mut Foo(0);
-   |             ^^^^
-   |
-   = note: see issue #123076 <https://github.com/rust-lang/rust/issues/123076> for more information
-   = help: add `#![feature(mut_ref)]` 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[E0277]: the trait bound `&_: main::Ref` is not satisfied
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:82:14
-   |
-LL |     let &_ = generic();
-   |              ^^^^^^^^^ the trait `main::Ref` is not implemented for `&_`
-   |
-   = help: the trait `main::Ref` is implemented for `&'static mut [(); 0]`
-note: required by a bound in `generic`
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:68:19
-   |
-LL |     fn generic<R: Ref>() -> R {
-   |                   ^^^ required by this bound in `generic`
-
-error: aborting due to 16 previous errors
-
-Some errors have detailed explanations: E0277, E0308, E0658.
-For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/mir/lint/storage-live.stderr b/tests/ui/mir/lint/storage-live.stderr
index c7012319512..651b8e2327e 100644
--- a/tests/ui/mir/lint/storage-live.stderr
+++ b/tests/ui/mir/lint/storage-live.stderr
@@ -1,4 +1,4 @@
-error: internal compiler error: broken MIR in Item(DefId(0:8 ~ storage_live[HASH]::multiple_storage)) (after pass CheckPackedRef) at bb0[1]:
+error: internal compiler error: broken MIR in Item(DefId(0:8 ~ storage_live[HASH]::multiple_storage)) (after pass CheckForceInline) at bb0[1]:
                                 StorageLive(_1) which already has storage here
   --> $DIR/storage-live.rs:23:13
    |
diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed
new file mode 100644
index 00000000000..7383ab177dc
--- /dev/null
+++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed
@@ -0,0 +1,12 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+//@[current] run-rustfix
+fn main() {
+    let _ = (-10..=10).find(|x: &i32| x.signum() == 0);
+    //[current]~^ ERROR type mismatch in closure arguments
+    //[next]~^^ ERROR expected a `FnMut(&<RangeInclusive<{integer}> as Iterator>::Item)` closure, found
+    let _ = (-10..=10).find(|x: &i32| x.signum() == 0);
+    //[current]~^ ERROR type mismatch in closure arguments
+    //[next]~^^ ERROR expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}`
+}
diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.stderr
index e52e095e9f7..c35d70a635c 100644
--- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.stderr
+++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.stderr
@@ -1,5 +1,5 @@
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/closure-arg-type-mismatch-issue-45727.rs:3:24
+  --> $DIR/closure-arg-type-mismatch-issue-45727.rs:6:24
    |
 LL |     let _ = (-10..=10).find(|x: i32| x.signum() == 0);
    |                        ^^^^ -------- found signature defined here
@@ -16,7 +16,7 @@ LL |     let _ = (-10..=10).find(|x: &i32| x.signum() == 0);
    |                                 +
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/closure-arg-type-mismatch-issue-45727.rs:4:24
+  --> $DIR/closure-arg-type-mismatch-issue-45727.rs:9:24
    |
 LL |     let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0);
    |                        ^^^^ ----------- found signature defined here
diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.fixed b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.fixed
deleted file mode 100644
index e6e3e1551e9..00000000000
--- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.fixed
+++ /dev/null
@@ -1,5 +0,0 @@
-//@ run-rustfix
-fn main() {
-    let _ = (-10..=10).find(|x: &i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments
-    let _ = (-10..=10).find(|x: &i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments
-}
diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr
new file mode 100644
index 00000000000..6104a089337
--- /dev/null
+++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr
@@ -0,0 +1,24 @@
+error[E0277]: expected a `FnMut(&<RangeInclusive<{integer}> as Iterator>::Item)` closure, found `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:6:29: 6:37}`
+  --> $DIR/closure-arg-type-mismatch-issue-45727.rs:6:29
+   |
+LL |     let _ = (-10..=10).find(|x: i32| x.signum() == 0);
+   |                        ---- ^^^^^^^^^^^^^^^^^^^^^^^^ expected an `FnMut(&<RangeInclusive<{integer}> as Iterator>::Item)` closure, found `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:6:29: 6:37}`
+   |                        |
+   |                        required by a bound introduced by this call
+   |
+   = help: the trait `for<'a> FnMut(&'a <RangeInclusive<{integer}> as Iterator>::Item)` is not implemented for closure `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:6:29: 6:37}`
+   = note: expected a closure with arguments `(i32,)`
+              found a closure with arguments `(&<RangeInclusive<{integer}> as Iterator>::Item,)`
+note: required by a bound in `find`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+
+error[E0271]: expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}`
+  --> $DIR/closure-arg-type-mismatch-issue-45727.rs:9:33
+   |
+LL |     let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0);
+   |                                 ^^^^^^ expected `&&i32`, found integer
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0271, E0277.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs
index 64e815606d4..668a1a7a29c 100644
--- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs
+++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs
@@ -1,5 +1,12 @@
-//@ run-rustfix
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+//@[current] run-rustfix
 fn main() {
-    let _ = (-10..=10).find(|x: i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments
-    let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments
+    let _ = (-10..=10).find(|x: i32| x.signum() == 0);
+    //[current]~^ ERROR type mismatch in closure arguments
+    //[next]~^^ ERROR expected a `FnMut(&<RangeInclusive<{integer}> as Iterator>::Item)` closure, found
+    let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0);
+    //[current]~^ ERROR type mismatch in closure arguments
+    //[next]~^^ ERROR expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}`
 }
diff --git a/tests/ui/modules/path-no-file-name.rs b/tests/ui/modules/path-no-file-name.rs
index 23127346e02..753a0950123 100644
--- a/tests/ui/modules/path-no-file-name.rs
+++ b/tests/ui/modules/path-no-file-name.rs
@@ -1,4 +1,4 @@
-//@ normalize-stderr: "\.:.*\(" -> ".: $$ACCESS_DENIED_MSG ("
+//@ normalize-stderr: "\.`:.*\(" -> ".`: $$ACCESS_DENIED_MSG ("
 //@ normalize-stderr: "os error \d+" -> "os error $$ACCESS_DENIED_CODE"
 
 #[path = "."]
diff --git a/tests/ui/modules/path-no-file-name.stderr b/tests/ui/modules/path-no-file-name.stderr
index 834e8ea6b03..6274ecfed13 100644
--- a/tests/ui/modules/path-no-file-name.stderr
+++ b/tests/ui/modules/path-no-file-name.stderr
@@ -1,4 +1,4 @@
-error: couldn't read $DIR/.: $ACCESS_DENIED_MSG (os error $ACCESS_DENIED_CODE)
+error: couldn't read `$DIR/.`: $ACCESS_DENIED_MSG (os error $ACCESS_DENIED_CODE)
   --> $DIR/path-no-file-name.rs:5:1
    |
 LL | mod m;
diff --git a/tests/ui/parser/issues/issue-5806.rs b/tests/ui/parser/issues/issue-5806.rs
index dbd53a7adc4..1a819e22197 100644
--- a/tests/ui/parser/issues/issue-5806.rs
+++ b/tests/ui/parser/issues/issue-5806.rs
@@ -1,4 +1,4 @@
-//@ normalize-stderr: "parser:.*\(" -> "parser: $$ACCESS_DENIED_MSG ("
+//@ normalize-stderr: "parser`:.*\(" -> "parser`: $$ACCESS_DENIED_MSG ("
 //@ normalize-stderr: "os error \d+" -> "os error $$ACCESS_DENIED_CODE"
 
 #[path = "../parser"]
diff --git a/tests/ui/parser/issues/issue-5806.stderr b/tests/ui/parser/issues/issue-5806.stderr
index 4b025bd19a0..88cc982baf2 100644
--- a/tests/ui/parser/issues/issue-5806.stderr
+++ b/tests/ui/parser/issues/issue-5806.stderr
@@ -1,4 +1,4 @@
-error: couldn't read $DIR/../parser: $ACCESS_DENIED_MSG (os error $ACCESS_DENIED_CODE)
+error: couldn't read `$DIR/../parser`: $ACCESS_DENIED_MSG (os error $ACCESS_DENIED_CODE)
   --> $DIR/issue-5806.rs:5:1
    |
 LL | mod foo;
diff --git a/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr b/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr
index 76259b40a93..dda37d83282 100644
--- a/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr
+++ b/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr
@@ -30,7 +30,7 @@ error: `mut` must be followed by a named binding
   --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:13:13
    |
 LL |         let mut $eval = ();
-   |             ^^^
+   |             ^^^^
 ...
 LL |     mac2! { does_not_exist!() }
    |     --------------------------- in this macro invocation
@@ -40,7 +40,7 @@ LL |     mac2! { does_not_exist!() }
 help: remove the `mut` prefix
    |
 LL -         let mut $eval = ();
-LL +         let  $eval = ();
+LL +         let $eval = ();
    |
 
 error: cannot find macro `does_not_exist` in this scope
diff --git a/tests/ui/parser/mod_file_with_path_attr.rs b/tests/ui/parser/mod_file_with_path_attr.rs
index ff964f750e2..b7f4a9c6ae0 100644
--- a/tests/ui/parser/mod_file_with_path_attr.rs
+++ b/tests/ui/parser/mod_file_with_path_attr.rs
@@ -1,4 +1,4 @@
-//@ normalize-stderr: "not_a_real_file.rs:.*\(" -> "not_a_real_file.rs: $$FILE_NOT_FOUND_MSG ("
+//@ normalize-stderr: "not_a_real_file.rs`:.*\(" -> "not_a_real_file.rs`: $$FILE_NOT_FOUND_MSG ("
 
 #[path = "not_a_real_file.rs"]
 mod m; //~ ERROR not_a_real_file.rs
diff --git a/tests/ui/parser/mod_file_with_path_attr.stderr b/tests/ui/parser/mod_file_with_path_attr.stderr
index 9ccb775daab..ef8a715712b 100644
--- a/tests/ui/parser/mod_file_with_path_attr.stderr
+++ b/tests/ui/parser/mod_file_with_path_attr.stderr
@@ -1,4 +1,4 @@
-error: couldn't read $DIR/not_a_real_file.rs: $FILE_NOT_FOUND_MSG (os error 2)
+error: couldn't read `$DIR/not_a_real_file.rs`: $FILE_NOT_FOUND_MSG (os error 2)
   --> $DIR/mod_file_with_path_attr.rs:4:1
    |
 LL | mod m;
diff --git a/tests/ui/pattern/no_ref_mut_behind_and.rs b/tests/ui/pattern/no_ref_mut_behind_and.rs
deleted file mode 100644
index c18d64904d0..00000000000
--- a/tests/ui/pattern/no_ref_mut_behind_and.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ edition: 2021
-//@ run-pass
-#![allow(incomplete_features)]
-#![feature(ref_pat_eat_one_layer_2024)]
-
-fn main() {
-    let &[[x]] = &[&mut [42]];
-    let _: &i32 = x;
-}
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic.stderr
index a8b81394110..c6246114075 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.stderr
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of a shared reference
-  --> $DIR/ref_pat_eat_one_layer_2024_fail2.rs:6:29
+  --> $DIR/borrowck-errors.rs:9:29
    |
 LL |     if let Some(&Some(x)) = Some(&Some(&mut 0)) {
    |                       -     ^^^^^^^^^^^^^^^^^^^
@@ -14,7 +14,7 @@ LL +     if let Some(Some(x)) = Some(&Some(&mut 0)) {
    |
 
 error[E0596]: cannot borrow data in a `&` reference as mutable
-  --> $DIR/ref_pat_eat_one_layer_2024_fail2.rs:11:10
+  --> $DIR/borrowck-errors.rs:14:10
    |
 LL |     let &ref mut x = &0;
    |          ^^^^^^^^^ cannot borrow as mutable
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.rs
index 79403b19365..a01e9ca2657 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.rs
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.rs
@@ -1,6 +1,9 @@
 //@ edition: 2024
+//@ revisions: classic structural
+//! Tests for pattern errors not handled by the pattern typing rules, but by borrowck.
 #![allow(incomplete_features)]
-#![feature(ref_pat_eat_one_layer_2024)]
+#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))]
+#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
 
 pub fn main() {
     if let Some(&Some(x)) = Some(&Some(&mut 0)) {
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural.stderr
new file mode 100644
index 00000000000..c6246114075
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural.stderr
@@ -0,0 +1,25 @@
+error[E0507]: cannot move out of a shared reference
+  --> $DIR/borrowck-errors.rs:9:29
+   |
+LL |     if let Some(&Some(x)) = Some(&Some(&mut 0)) {
+   |                       -     ^^^^^^^^^^^^^^^^^^^
+   |                       |
+   |                       data moved here
+   |                       move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait
+   |
+help: consider removing the borrow
+   |
+LL -     if let Some(&Some(x)) = Some(&Some(&mut 0)) {
+LL +     if let Some(Some(x)) = Some(&Some(&mut 0)) {
+   |
+
+error[E0596]: cannot borrow data in a `&` reference as mutable
+  --> $DIR/borrowck-errors.rs:14:10
+   |
+LL |     let &ref mut x = &0;
+   |          ^^^^^^^^^ cannot borrow as mutable
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0507, E0596.
+For more information about an error, try `rustc --explain E0507`.
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.classic.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.classic.stderr
new file mode 100644
index 00000000000..89a52ba7d1d
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.classic.stderr
@@ -0,0 +1,58 @@
+error[E0308]: mismatched types
+  --> $DIR/cannot-mutably-deref-shared-ref.rs:9:9
+   |
+LL |     let &mut _ = &&0;
+   |         ^^^^^^   --- this expression has type `&&{integer}`
+   |         |
+   |         types differ in mutability
+   |
+   = note:      expected reference `&&{integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/cannot-mutably-deref-shared-ref.rs:12:9
+   |
+LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
+   |         ^^^^^^   ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
+   |         |
+   |         types differ in mutability
+   |
+   = note:      expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/cannot-mutably-deref-shared-ref.rs:15:9
+   |
+LL |     let &mut _ = &&mut 0;
+   |         ^^^^^^   ------- this expression has type `&&mut {integer}`
+   |         |
+   |         types differ in mutability
+   |
+   = note:      expected reference `&&mut {integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/cannot-mutably-deref-shared-ref.rs:18:9
+   |
+LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0;
+   |         ^^^^^^   --------------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}`
+   |         |
+   |         types differ in mutability
+   |
+   = note:      expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/cannot-mutably-deref-shared-ref.rs:21:14
+   |
+LL |     let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0;
+   |              ^^^^^^^^^^^^^^^^   -------------------------- this expression has type `&mut &&&&mut &&&mut &mut {integer}`
+   |              |
+   |              types differ in mutability
+   |
+   = note:      expected reference `&&&&mut &&&mut &mut {integer}`
+           found mutable reference `&mut _`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.rs
new file mode 100644
index 00000000000..e22bd1f8f6c
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.rs
@@ -0,0 +1,23 @@
+//@ edition: 2024
+//@ revisions: classic structural
+//! Test that `&mut` patterns don't match shared reference types under new typing rules in Rust 2024
+#![allow(incomplete_features)]
+#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))]
+#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
+
+pub fn main() {
+    let &mut _ = &&0;
+    //~^ ERROR: mismatched types
+
+    let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
+    //~^ ERROR: mismatched types
+
+    let &mut _ = &&mut 0;
+    //~^ ERROR: mismatched types
+
+    let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0;
+    //~^ ERROR: mismatched types
+
+    let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0;
+    //~^ ERROR: mismatched types
+}
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.structural.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.structural.stderr
new file mode 100644
index 00000000000..89a52ba7d1d
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.structural.stderr
@@ -0,0 +1,58 @@
+error[E0308]: mismatched types
+  --> $DIR/cannot-mutably-deref-shared-ref.rs:9:9
+   |
+LL |     let &mut _ = &&0;
+   |         ^^^^^^   --- this expression has type `&&{integer}`
+   |         |
+   |         types differ in mutability
+   |
+   = note:      expected reference `&&{integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/cannot-mutably-deref-shared-ref.rs:12:9
+   |
+LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
+   |         ^^^^^^   ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
+   |         |
+   |         types differ in mutability
+   |
+   = note:      expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/cannot-mutably-deref-shared-ref.rs:15:9
+   |
+LL |     let &mut _ = &&mut 0;
+   |         ^^^^^^   ------- this expression has type `&&mut {integer}`
+   |         |
+   |         types differ in mutability
+   |
+   = note:      expected reference `&&mut {integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/cannot-mutably-deref-shared-ref.rs:18:9
+   |
+LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0;
+   |         ^^^^^^   --------------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}`
+   |         |
+   |         types differ in mutability
+   |
+   = note:      expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/cannot-mutably-deref-shared-ref.rs:21:14
+   |
+LL |     let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0;
+   |              ^^^^^^^^^^^^^^^^   -------------------------- this expression has type `&mut &&&&mut &&&mut &mut {integer}`
+   |              |
+   |              types differ in mutability
+   |
+   = note:      expected reference `&&&&mut &&&mut &mut {integer}`
+           found mutable reference `&mut _`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/feature-gate-ref_pat_eat_one_layer_2024.rs
index bc12d69b105..bc12d69b105 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/feature-gate-ref_pat_eat_one_layer_2024.rs
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/feature-gate-ref_pat_eat_one_layer_2024.stderr
index 132fe421a18..132fe421a18 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/feature-gate-ref_pat_eat_one_layer_2024.stderr
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.classic.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.classic.stderr
new file mode 100644
index 00000000000..43560a18030
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.classic.stderr
@@ -0,0 +1,23 @@
+error[E0658]: binding cannot be both mutable and by-reference
+  --> $DIR/mut-ref-mut.rs:11:13
+   |
+LL |     let Foo(mut a) = &Foo(0);
+   |             ^^^^
+   |
+   = note: see issue #123076 <https://github.com/rust-lang/rust/issues/123076> for more information
+   = help: add `#![feature(mut_ref)]` 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]: binding cannot be both mutable and by-reference
+  --> $DIR/mut-ref-mut.rs:15:13
+   |
+LL |     let Foo(mut a) = &mut Foo(0);
+   |             ^^^^
+   |
+   = note: see issue #123076 <https://github.com/rust-lang/rust/issues/123076> for more information
+   = help: add `#![feature(mut_ref)]` 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/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs
new file mode 100644
index 00000000000..786587984ba
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs
@@ -0,0 +1,18 @@
+//@ edition: 2024
+//@ revisions: classic structural
+//! Test diagnostics for binding with `mut` when the default binding mode is by-ref.
+#![allow(incomplete_features)]
+#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))]
+#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
+
+pub fn main() {
+    struct Foo(u8);
+
+    let Foo(mut a) = &Foo(0);
+    //~^ ERROR: binding cannot be both mutable and by-reference
+    a = &42;
+
+    let Foo(mut a) = &mut Foo(0);
+    //~^ ERROR: binding cannot be both mutable and by-reference
+    a = &mut 42;
+}
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.structural.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.structural.stderr
new file mode 100644
index 00000000000..43560a18030
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.structural.stderr
@@ -0,0 +1,23 @@
+error[E0658]: binding cannot be both mutable and by-reference
+  --> $DIR/mut-ref-mut.rs:11:13
+   |
+LL |     let Foo(mut a) = &Foo(0);
+   |             ^^^^
+   |
+   = note: see issue #123076 <https://github.com/rust-lang/rust/issues/123076> for more information
+   = help: add `#![feature(mut_ref)]` 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]: binding cannot be both mutable and by-reference
+  --> $DIR/mut-ref-mut.rs:15:13
+   |
+LL |     let Foo(mut a) = &mut Foo(0);
+   |             ^^^^
+   |
+   = note: see issue #123076 <https://github.com/rust-lang/rust/issues/123076> for more information
+   = help: add `#![feature(mut_ref)]` 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/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic.stderr
new file mode 100644
index 00000000000..2bc3ecb7636
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic.stderr
@@ -0,0 +1,111 @@
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:15:17
+   |
+LL |     if let Some(&mut x) = &Some(&mut 0) {
+   |                 ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     if let Some(&x) = &Some(&mut 0) {
+   |                 ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:19:17
+   |
+LL |     if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
+   |                 ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     if let Some(&Some(&x)) = &Some(&mut Some(0)) {
+   |                 ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:23:22
+   |
+LL |     if let Some(Some(&mut x)) = &Some(Some(&mut 0)) {
+   |                      ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     if let Some(Some(&x)) = &Some(Some(&mut 0)) {
+   |                      ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:28:17
+   |
+LL |     if let Some(&mut Some(&_)) = &Some(&Some(0)) {
+   |                 ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     if let Some(&Some(&_)) = &Some(&Some(0)) {
+   |                 ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:31:23
+   |
+LL |     if let Some(&Some(&mut _)) = &Some(&mut Some(0)) {
+   |                       ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     if let Some(&Some(&_)) = &Some(&mut Some(0)) {
+   |                       ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:34:23
+   |
+LL |     if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
+   |                       ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     if let Some(&Some(&_)) = &mut Some(&Some(0)) {
+   |                       ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:37:29
+   |
+LL |     if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
+   |                             ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     if let Some(&Some(Some((&_)))) = &Some(Some(&mut Some(0))) {
+   |                             ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:40:17
+   |
+LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
+   |                 ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     if let Some(&Some(x)) = &Some(Some(0)) {
+   |                 ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:43:17
+   |
+LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
+   |                 ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     if let Some(&Some(x)) = &Some(Some(0)) {
+   |                 ~
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs
new file mode 100644
index 00000000000..3535ba9c701
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs
@@ -0,0 +1,46 @@
+//@ edition: 2024
+//@ revisions: classic structural
+//! Test cases for poorly-typed patterns in edition 2024 which are caught by HIR typeck. These must
+//! be separate from cases caught by MIR borrowck or the latter errors may not be emitted.
+#![allow(incomplete_features)]
+#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))]
+#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
+
+pub fn main() {
+    if let Some(&mut x) = &mut Some(&0) {
+        //[structural]~^ ERROR: mismatched types
+        let _: &u32 = x;
+    }
+
+    if let Some(&mut x) = &Some(&mut 0) {
+        //[classic]~^ ERROR: mismatched types
+        let _: &u32 = x;
+    }
+    if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
+        //[classic]~^ ERROR: mismatched types
+        let _: u32 = x;
+    }
+    if let Some(Some(&mut x)) = &Some(Some(&mut 0)) {
+        //[classic]~^ ERROR: mismatched types
+        let _: &u32 = x;
+    }
+
+    if let Some(&mut Some(&_)) = &Some(&Some(0)) {
+        //~^ ERROR: mismatched types
+    }
+    if let Some(&Some(&mut _)) = &Some(&mut Some(0)) {
+        //~^ ERROR: mismatched types
+    }
+    if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
+        //~^ ERROR: mismatched types
+    }
+    if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
+        //~^ ERROR: mismatched types
+    }
+    if let Some(&mut Some(x)) = &Some(Some(0)) {
+        //~^ ERROR: mismatched types
+    }
+    if let Some(&mut Some(x)) = &Some(Some(0)) {
+        //~^ ERROR: mismatched types
+    }
+}
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural.stderr
new file mode 100644
index 00000000000..59d65553fae
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural.stderr
@@ -0,0 +1,89 @@
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:10:17
+   |
+LL |     if let Some(&mut x) = &mut Some(&0) {
+   |                 ^^^^^^    ------------- this expression has type `&mut Option<&{integer}>`
+   |                 |
+   |                 types differ in mutability
+   |
+   = note:      expected reference `&{integer}`
+           found mutable reference `&mut _`
+note: to declare a mutable binding use: `mut x`
+  --> $DIR/pattern-errors.rs:10:17
+   |
+LL |     if let Some(&mut x) = &mut Some(&0) {
+   |                 ^^^^^^
+help: consider removing `&mut` from the pattern
+   |
+LL |     if let Some(x) = &mut Some(&0) {
+   |                 ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:28:17
+   |
+LL |     if let Some(&mut Some(&_)) = &Some(&Some(0)) {
+   |                 ^^^^^^^^^^^^^    --------------- this expression has type `&Option<&Option<{integer}>>`
+   |                 |
+   |                 types differ in mutability
+   |
+   = note:      expected reference `&Option<{integer}>`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:31:23
+   |
+LL |     if let Some(&Some(&mut _)) = &Some(&mut Some(0)) {
+   |                       ^^^^^^     ------------------- this expression has type `&Option<&mut Option<{integer}>>`
+   |                       |
+   |                       expected integer, found `&mut _`
+   |
+   = note:           expected type `{integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:34:23
+   |
+LL |     if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
+   |                       ^^^^^^     ------------------- this expression has type `&mut Option<&Option<{integer}>>`
+   |                       |
+   |                       expected integer, found `&mut _`
+   |
+   = note:           expected type `{integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:37:29
+   |
+LL |     if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
+   |                             ^^^^^^       ------------------------- this expression has type `&Option<Option<&mut Option<{integer}>>>`
+   |                             |
+   |                             expected integer, found `&mut _`
+   |
+   = note:           expected type `{integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:40:17
+   |
+LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
+   |                 ^^^^^^^^^^^^    -------------- this expression has type `&Option<Option<{integer}>>`
+   |                 |
+   |                 expected `Option<{integer}>`, found `&mut _`
+   |
+   = note:           expected enum `Option<{integer}>`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:43:17
+   |
+LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
+   |                 ^^^^^^^^^^^^    -------------- this expression has type `&Option<Option<{integer}>>`
+   |                 |
+   |                 expected `Option<{integer}>`, found `&mut _`
+   |
+   = note:           expected enum `Option<{integer}>`
+           found mutable reference `&mut _`
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.fixed b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic.fixed
index e69d169966b..4f4941975d8 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.fixed
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic.fixed
@@ -1,7 +1,11 @@
 //@ edition: 2024
 //@ run-rustfix
+//@ revisions: classic structural
+//! Tests for `&` patterns matched against `&mut` reference types where the inner pattern attempts
+//! to bind by mutable reference.
 #![allow(incomplete_features)]
-#![feature(ref_pat_eat_one_layer_2024)]
+#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))]
+#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
 
 pub fn main() {
     if let Some(&mut Some(ref mut x)) = &mut Some(Some(0)) {
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic.stderr
index 8e135b65253..6c384a51fac 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.stderr
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic.stderr
@@ -1,5 +1,5 @@
 error[E0596]: cannot borrow as mutable inside an `&` pattern
-  --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:7:31
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:11:31
    |
 LL |     if let Some(&Some(ref mut x)) = &mut Some(Some(0)) {
    |                 -             ^
@@ -7,7 +7,7 @@ LL |     if let Some(&Some(ref mut x)) = &mut Some(Some(0)) {
    |                 help: replace this `&` with `&mut`: `&mut`
 
 error[E0596]: cannot borrow as mutable inside an `&` pattern
-  --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:12:31
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:16:31
    |
 LL |     if let &Some(Some(ref mut x)) = &mut Some(Some(0)) {
    |            -                  ^
@@ -15,7 +15,7 @@ LL |     if let &Some(Some(ref mut x)) = &mut Some(Some(0)) {
    |            help: replace this `&` with `&mut`: `&mut`
 
 error[E0596]: cannot borrow as mutable inside an `&` pattern
-  --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:20:15
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:24:15
    |
 LL |     let &pat!(x) = &mut 0;
    |         -     ^
@@ -23,7 +23,7 @@ LL |     let &pat!(x) = &mut 0;
    |         help: replace this `&` with `&mut`: `&mut`
 
 error[E0596]: cannot borrow as mutable inside an `&` pattern
-  --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:24:19
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:28:19
    |
 LL |     let &(ref mut a, ref mut b) = &mut (true, false);
    |         -         ^
@@ -31,7 +31,7 @@ LL |     let &(ref mut a, ref mut b) = &mut (true, false);
    |         help: replace this `&` with `&mut`: `&mut`
 
 error[E0596]: cannot borrow as mutable inside an `&` pattern
-  --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:24:30
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:28:30
    |
 LL |     let &(ref mut a, ref mut b) = &mut (true, false);
    |         -                    ^
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.rs
index a300cbcd4df..b29bff7603f 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.rs
@@ -1,7 +1,11 @@
 //@ edition: 2024
 //@ run-rustfix
+//@ revisions: classic structural
+//! Tests for `&` patterns matched against `&mut` reference types where the inner pattern attempts
+//! to bind by mutable reference.
 #![allow(incomplete_features)]
-#![feature(ref_pat_eat_one_layer_2024)]
+#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))]
+#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
 
 pub fn main() {
     if let Some(&Some(ref mut x)) = &mut Some(Some(0)) {
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.fixed b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.fixed
new file mode 100644
index 00000000000..4f4941975d8
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.fixed
@@ -0,0 +1,33 @@
+//@ edition: 2024
+//@ run-rustfix
+//@ revisions: classic structural
+//! Tests for `&` patterns matched against `&mut` reference types where the inner pattern attempts
+//! to bind by mutable reference.
+#![allow(incomplete_features)]
+#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))]
+#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
+
+pub fn main() {
+    if let Some(&mut Some(ref mut x)) = &mut Some(Some(0)) {
+        //~^ ERROR: cannot borrow as mutable inside an `&` pattern
+        let _: &mut u8 = x;
+    }
+
+    if let &mut Some(Some(ref mut x)) = &mut Some(Some(0)) {
+        //~^ ERROR: cannot borrow as mutable inside an `&` pattern
+        let _: &mut u8 = x;
+    }
+
+    macro_rules! pat {
+        ($var:ident) => { ref mut $var };
+    }
+    let &mut pat!(x) = &mut 0;
+    //~^ ERROR: cannot borrow as mutable inside an `&` pattern
+    let _: &mut u8 = x;
+
+    let &mut (ref mut a, ref mut b) = &mut (true, false);
+    //~^ ERROR: cannot borrow as mutable inside an `&` pattern
+    //~| ERROR: cannot borrow as mutable inside an `&` pattern
+    let _: &mut bool = a;
+    let _: &mut bool = b;
+}
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.stderr
new file mode 100644
index 00000000000..6c384a51fac
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.stderr
@@ -0,0 +1,43 @@
+error[E0596]: cannot borrow as mutable inside an `&` pattern
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:11:31
+   |
+LL |     if let Some(&Some(ref mut x)) = &mut Some(Some(0)) {
+   |                 -             ^
+   |                 |
+   |                 help: replace this `&` with `&mut`: `&mut`
+
+error[E0596]: cannot borrow as mutable inside an `&` pattern
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:16:31
+   |
+LL |     if let &Some(Some(ref mut x)) = &mut Some(Some(0)) {
+   |            -                  ^
+   |            |
+   |            help: replace this `&` with `&mut`: `&mut`
+
+error[E0596]: cannot borrow as mutable inside an `&` pattern
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:24:15
+   |
+LL |     let &pat!(x) = &mut 0;
+   |         -     ^
+   |         |
+   |         help: replace this `&` with `&mut`: `&mut`
+
+error[E0596]: cannot borrow as mutable inside an `&` pattern
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:28:19
+   |
+LL |     let &(ref mut a, ref mut b) = &mut (true, false);
+   |         -         ^
+   |         |
+   |         help: replace this `&` with `&mut`: `&mut`
+
+error[E0596]: cannot borrow as mutable inside an `&` pattern
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:28:30
+   |
+LL |     let &(ref mut a, ref mut b) = &mut (true, false);
+   |         -                    ^
+   |         |
+   |         help: replace this `&` with `&mut`: `&mut`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021.rs
index afea249ffef..9372049a2b2 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.rs
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021.rs
@@ -1,9 +1,9 @@
 //@ run-pass
 //@ edition: 2021
-//@ revisions: classic structural both
+//@ revisions: classic structural
 #![allow(incomplete_features)]
-#![cfg_attr(any(classic, both), feature(ref_pat_eat_one_layer_2024))]
-#![cfg_attr(any(structural, both), feature(ref_pat_eat_one_layer_2024_structural))]
+#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))]
+#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
 
 pub fn main() {
     if let &Some(Some(x)) = &Some(&mut Some(0)) {
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021_fail.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021_fail.rs
index d28567f2859..d28567f2859 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021_fail.rs
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021_fail.rs
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021_fail.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021_fail.stderr
index 1a921234ea0..1a921234ea0 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021_fail.stderr
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021_fail.stderr
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/trait-selection-sanity.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/trait-selection-sanity.rs
new file mode 100644
index 00000000000..cb8fdb489c0
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/trait-selection-sanity.rs
@@ -0,0 +1,30 @@
+//@ edition: 2024
+//@ revisions: with_impl without_impl
+//@[with_impl] run-pass
+//! Sanity check that experimental new pattern typing rules work as expected with trait selection
+
+fn main() {
+    fn generic<R: Ref>() -> (R, bool) {
+        R::meow()
+    }
+
+    trait Ref: Sized {
+        fn meow() -> (Self, bool);
+    }
+
+    #[cfg(with_impl)]
+    impl Ref for &'static [(); 0] {
+        fn meow() -> (Self, bool) {
+            (&[], false)
+        }
+    }
+
+    impl Ref for &'static mut [(); 0] {
+        fn meow() -> (Self, bool) {
+            (&mut [], true)
+        }
+    }
+
+    let (&_, b) = generic(); //[without_impl]~ ERROR: the trait bound `&_: main::Ref` is not satisfied [E0277]
+    assert!(!b);
+}
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/trait-selection-sanity.without_impl.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/trait-selection-sanity.without_impl.stderr
new file mode 100644
index 00000000000..83e45221fac
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/trait-selection-sanity.without_impl.stderr
@@ -0,0 +1,16 @@
+error[E0277]: the trait bound `&_: main::Ref` is not satisfied
+  --> $DIR/trait-selection-sanity.rs:28:19
+   |
+LL |     let (&_, b) = generic();
+   |                   ^^^^^^^^^ the trait `main::Ref` is not implemented for `&_`
+   |
+   = help: the trait `main::Ref` is implemented for `&'static mut [(); 0]`
+note: required by a bound in `generic`
+  --> $DIR/trait-selection-sanity.rs:7:19
+   |
+LL |     fn generic<R: Ref>() -> (R, bool) {
+   |                   ^^^ required by this bound in `generic`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs
index b145446de0a..077b52d8f27 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs
@@ -1,9 +1,11 @@
-//@ run-pass
 //@ edition: 2024
-//@ revisions: classic structural both
+//@ revisions: classic structural
+//@ run-pass
+//! Test cases for well-typed patterns in edition 2024. These are in their own file to ensure we
+//! pass both HIR typeck and MIR borrowck, as we may skip the latter if grouped with failing tests.
 #![allow(incomplete_features)]
-#![cfg_attr(any(classic, both), feature(ref_pat_eat_one_layer_2024))]
-#![cfg_attr(any(structural, both), feature(ref_pat_eat_one_layer_2024_structural))]
+#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))]
+#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
 
 pub fn main() {
     if let Some(Some(&x)) = &Some(&Some(0)) {
@@ -54,35 +56,4 @@ pub fn main() {
     if let Some(&Some(x)) = &mut Some(Some(0)) {
         let _: u32 = x;
     }
-    #[cfg(any(classic, both))]
-    if let Some(&mut x) = &mut Some(&0) {
-        let _: &u32 = x;
-    }
-    #[cfg(any(structural, both))]
-    if let Some(&mut x) = &Some(&mut 0) {
-        let _: &u32 = x;
-    }
-
-    fn generic<R: Ref>() -> (R, bool) {
-        R::meow()
-    }
-
-    trait Ref: Sized {
-        fn meow() -> (Self, bool);
-    }
-
-    impl Ref for &'static [(); 0] {
-        fn meow() -> (Self, bool) {
-            (&[], false)
-        }
-    }
-
-    impl Ref for &'static mut [(); 0] {
-        fn meow() -> (Self, bool) {
-            (&mut [], true)
-        }
-    }
-
-    let (&_, b) = generic();
-    assert!(!b);
 }
diff --git a/tests/ui/pattern/usefulness/issue-82772-match-box-as-struct.stderr b/tests/ui/pattern/usefulness/issue-82772-match-box-as-struct.stderr
index ba7573839ed..ee21b4c8d46 100644
--- a/tests/ui/pattern/usefulness/issue-82772-match-box-as-struct.stderr
+++ b/tests/ui/pattern/usefulness/issue-82772-match-box-as-struct.stderr
@@ -2,7 +2,7 @@ error[E0451]: field `1` of struct `Box` is private
   --> $DIR/issue-82772-match-box-as-struct.rs:4:15
    |
 LL |     let Box { 1: _, .. }: Box<()>;
-   |               ^^^^ private field
+   |               ^ private field
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/print_type_sizes/anonymous.rs b/tests/ui/print_type_sizes/anonymous.rs
index a3a32228088..7819e5ea767 100644
--- a/tests/ui/print_type_sizes/anonymous.rs
+++ b/tests/ui/print_type_sizes/anonymous.rs
@@ -1,14 +1,13 @@
-//@ compile-flags: -Z print-type-sizes
+//@ compile-flags: -Z print-type-sizes --crate-type=lib
 //@ build-pass
 
 // All of the types that occur in this function are uninteresting, in
 // that one cannot control the sizes of these types with the same sort
 // of enum-variant manipulation tricks.
 
-#![feature(start)]
+#![no_std]
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+pub fn main() -> isize {
     let _byte: u8 = 0;
     let _word: usize = 0;
     let _tuple: (u8, usize)= (0, 0);
diff --git a/tests/ui/privacy/privacy1.rs b/tests/ui/privacy/privacy1.rs
index 31f39601003..9436441ecc6 100644
--- a/tests/ui/privacy/privacy1.rs
+++ b/tests/ui/privacy/privacy1.rs
@@ -1,4 +1,4 @@
-#![feature(lang_items, start, no_core)]
+#![feature(lang_items, no_core)]
 #![no_core] // makes debugging this test *a lot* easier (during resolve)
 
 #[lang="sized"]
@@ -173,4 +173,4 @@ pub mod mytest {
     }
 }
 
-#[start] fn main(_: isize, _: *const *const u8) -> isize { 3 }
+fn main() {}
diff --git a/tests/ui/privacy/privacy2.rs b/tests/ui/privacy/privacy2.rs
index 33292a65c5d..ab6d805544e 100644
--- a/tests/ui/privacy/privacy2.rs
+++ b/tests/ui/privacy/privacy2.rs
@@ -1,6 +1,6 @@
 //@ compile-flags: -Zdeduplicate-diagnostics=yes
 
-#![feature(start, no_core)]
+#![feature(no_core)]
 #![no_core] // makes debugging this test *a lot* easier (during resolve)
 
 // Test to make sure that globs don't leak in regular `use` statements.
@@ -26,4 +26,4 @@ fn test2() {
     //~^ ERROR `foo` is private
 }
 
-#[start] fn main(_: isize, _: *const *const u8) -> isize { 3 }
+fn main() {}
diff --git a/tests/ui/privacy/privacy3.rs b/tests/ui/privacy/privacy3.rs
index fb1f432410d..6298a6bc8cf 100644
--- a/tests/ui/privacy/privacy3.rs
+++ b/tests/ui/privacy/privacy3.rs
@@ -1,6 +1,6 @@
 //@ compile-flags: -Zdeduplicate-diagnostics=yes
 
-#![feature(start, no_core)]
+#![feature( no_core)]
 #![no_core] // makes debugging this test *a lot* easier (during resolve)
 
 // Test to make sure that private items imported through globs remain private
@@ -26,4 +26,4 @@ fn test1() {
     gpriv();
 }
 
-#[start] fn main(_: isize, _: *const *const u8) -> isize { 3 }
+fn main() {}
diff --git a/tests/ui/privacy/privacy4.rs b/tests/ui/privacy/privacy4.rs
index fa257b80039..7341c7752bb 100644
--- a/tests/ui/privacy/privacy4.rs
+++ b/tests/ui/privacy/privacy4.rs
@@ -1,4 +1,4 @@
-#![feature(lang_items, start, no_core)]
+#![feature(lang_items, no_core)]
 #![no_core] // makes debugging this test *a lot* easier (during resolve)
 
 #[lang = "sized"] pub trait Sized {}
@@ -22,4 +22,4 @@ fn test2() {
     gpriv();
 }
 
-#[start] fn main(_: isize, _: *const *const u8) -> isize { 3 }
+fn main() {}
diff --git a/tests/ui/privacy/private-struct-field-ctor.stderr b/tests/ui/privacy/private-struct-field-ctor.stderr
index 2a35537237a..8eb1bf7990b 100644
--- a/tests/ui/privacy/private-struct-field-ctor.stderr
+++ b/tests/ui/privacy/private-struct-field-ctor.stderr
@@ -2,7 +2,7 @@ error[E0451]: field `x` of struct `Foo` is private
   --> $DIR/private-struct-field-ctor.rs:8:22
    |
 LL |     let s = a::Foo { x: 1 };
-   |                      ^^^^ private field
+   |                      ^ private field
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/privacy/private-struct-field-pattern.stderr b/tests/ui/privacy/private-struct-field-pattern.stderr
index de24d1e0962..5609596721d 100644
--- a/tests/ui/privacy/private-struct-field-pattern.stderr
+++ b/tests/ui/privacy/private-struct-field-pattern.stderr
@@ -2,7 +2,7 @@ error[E0451]: field `x` of struct `Foo` is private
   --> $DIR/private-struct-field-pattern.rs:15:15
    |
 LL |         Foo { x: _ } => {}
-   |               ^^^^ private field
+   |               ^ private field
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/privacy/restricted/struct-literal-field.stderr b/tests/ui/privacy/restricted/struct-literal-field.stderr
index dcdadf1da4b..e1cf7c2fadb 100644
--- a/tests/ui/privacy/restricted/struct-literal-field.stderr
+++ b/tests/ui/privacy/restricted/struct-literal-field.stderr
@@ -2,7 +2,7 @@ error[E0451]: field `x` of struct `S` is private
   --> $DIR/struct-literal-field.rs:18:9
    |
 LL |     S { x: 0 };
-   |         ^^^^ private field
+   |         ^ private field
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/privacy/union-field-privacy-1.stderr b/tests/ui/privacy/union-field-privacy-1.stderr
index b1f0b785ea7..6f883b16d02 100644
--- a/tests/ui/privacy/union-field-privacy-1.stderr
+++ b/tests/ui/privacy/union-field-privacy-1.stderr
@@ -2,7 +2,7 @@ error[E0451]: field `c` of union `U` is private
   --> $DIR/union-field-privacy-1.rs:12:20
    |
 LL |     let u = m::U { c: 0 };
-   |                    ^^^^ private field
+   |                    ^ private field
 
 error[E0451]: field `c` of union `U` is private
   --> $DIR/union-field-privacy-1.rs:16:16
diff --git a/tests/ui/proc-macro/inner-attr-non-inline-mod.rs b/tests/ui/proc-macro/inner-attr-non-inline-mod.rs
index 714463b6225..d4336a7f3e1 100644
--- a/tests/ui/proc-macro/inner-attr-non-inline-mod.rs
+++ b/tests/ui/proc-macro/inner-attr-non-inline-mod.rs
@@ -1,7 +1,6 @@
 //@ compile-flags: -Z span-debug
 //@ error-pattern:custom inner attributes are unstable
 //@ error-pattern:inner macro attributes are unstable
-//@ error-pattern:this was previously accepted
 //@ proc-macro: test-macros.rs
 
 #![no_std] // Don't load unnecessary hygiene information from std
diff --git a/tests/ui/proc-macro/inner-attr-non-inline-mod.stderr b/tests/ui/proc-macro/inner-attr-non-inline-mod.stderr
index ccc967aaff9..025eec24818 100644
--- a/tests/ui/proc-macro/inner-attr-non-inline-mod.stderr
+++ b/tests/ui/proc-macro/inner-attr-non-inline-mod.stderr
@@ -1,3 +1,13 @@
+error[E0658]: custom inner attributes are unstable
+  --> $DIR/module_with_attrs.rs:3:4
+   |
+LL | #![rustfmt::skip]
+   |    ^^^^^^^^^^^^^
+   |
+   = note: see issue #54726 <https://github.com/rust-lang/rust/issues/54726> for more information
+   = help: add `#![feature(custom_inner_attributes)]` 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]: inner macro attributes are unstable
   --> $DIR/module_with_attrs.rs:4:4
    |
@@ -9,7 +19,7 @@ LL | #![print_attr]
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: non-inline modules in proc macro input are unstable
-  --> $DIR/inner-attr-non-inline-mod.rs:14:1
+  --> $DIR/inner-attr-non-inline-mod.rs:13:1
    |
 LL | mod module_with_attrs;
    | ^^^^^^^^^^^^^^^^^^^^^^
@@ -19,7 +29,7 @@ LL | mod module_with_attrs;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: custom inner attributes are unstable
-  --> $DIR/inner-attr-non-inline-mod.rs:14:1
+  --> $DIR/inner-attr-non-inline-mod.rs:13:1
    |
 LL | mod module_with_attrs;
    | ^^^^^^^^^^^^^^^^^^^^^^
@@ -28,27 +38,6 @@ LL | mod module_with_attrs;
    = help: add `#![feature(custom_inner_attributes)]` 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: custom inner attributes are unstable
-  --> $DIR/module_with_attrs.rs:3:4
-   |
-LL | #![rustfmt::skip]
-   |    ^^^^^^^^^^^^^
-   |
-   = 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 #64266 <https://github.com/rust-lang/rust/issues/64266>
-   = note: `#[deny(soft_unstable)]` on by default
-
 error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
-Future incompatibility report: Future breakage diagnostic:
-error: custom inner attributes are unstable
-  --> $DIR/module_with_attrs.rs:3:4
-   |
-LL | #![rustfmt::skip]
-   |    ^^^^^^^^^^^^^
-   |
-   = 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 #64266 <https://github.com/rust-lang/rust/issues/64266>
-   = note: `#[deny(soft_unstable)]` on by default
-
diff --git a/tests/ui/proc-macro/inner-attr-non-inline-mod.stdout b/tests/ui/proc-macro/inner-attr-non-inline-mod.stdout
index aaec40669e6..450542f68c6 100644
--- a/tests/ui/proc-macro/inner-attr-non-inline-mod.stdout
+++ b/tests/ui/proc-macro/inner-attr-non-inline-mod.stdout
@@ -4,35 +4,35 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
+        span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "deny",
-                span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
+                span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "unused_attributes",
-                        span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
+                        span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
                     },
                 ],
-                span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
+                span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
             },
         ],
-        span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
+        span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
     },
     Ident {
         ident: "mod",
-        span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
+        span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
     },
     Ident {
         ident: "module_with_attrs",
-        span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
+        span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
     },
     Group {
         delimiter: Brace,
@@ -40,38 +40,38 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
+                span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
+                span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "rustfmt",
-                        span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
+                        span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
                     },
                     Punct {
                         ch: ':',
                         spacing: Joint,
-                        span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
+                        span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
                     },
                     Punct {
                         ch: ':',
                         spacing: Alone,
-                        span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
+                        span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
                     },
                     Ident {
                         ident: "skip",
-                        span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
+                        span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
                     },
                 ],
-                span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
+                span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
             },
         ],
-        span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
+        span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
     },
 ]
diff --git a/tests/ui/proc-macro/proc-macro-gates.rs b/tests/ui/proc-macro/proc-macro-gates.rs
index bf384bc479b..04e097eb2f7 100644
--- a/tests/ui/proc-macro/proc-macro-gates.rs
+++ b/tests/ui/proc-macro/proc-macro-gates.rs
@@ -47,7 +47,6 @@ fn attrs() {
 
 fn test_case() {
     #![test] //~ ERROR inner macro attributes are unstable
-             //~| WARN this was previously accepted
 }
 
 fn main() {}
diff --git a/tests/ui/proc-macro/proc-macro-gates.stderr b/tests/ui/proc-macro/proc-macro-gates.stderr
index a05a7d0b185..3607b062a5f 100644
--- a/tests/ui/proc-macro/proc-macro-gates.stderr
+++ b/tests/ui/proc-macro/proc-macro-gates.stderr
@@ -84,27 +84,16 @@ LL |     let _x = #[identity_attr] println!();
    = help: add `#![feature(proc_macro_hygiene)]` 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: inner macro attributes are unstable
+error[E0658]: inner macro attributes are unstable
   --> $DIR/proc-macro-gates.rs:49:8
    |
 LL |     #![test]
    |        ^^^^
    |
-   = 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 #64266 <https://github.com/rust-lang/rust/issues/64266>
-   = note: `#[deny(soft_unstable)]` on by default
+   = note: see issue #54726 <https://github.com/rust-lang/rust/issues/54726> for more information
+   = help: add `#![feature(custom_inner_attributes)]` 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 10 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
-Future incompatibility report: Future breakage diagnostic:
-error: inner macro attributes are unstable
-  --> $DIR/proc-macro-gates.rs:49:8
-   |
-LL |     #![test]
-   |        ^^^^
-   |
-   = 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 #64266 <https://github.com/rust-lang/rust/issues/64266>
-   = note: `#[deny(soft_unstable)]` on by default
-
diff --git a/tests/ui/resolve/auxiliary/fake_matches.rs b/tests/ui/resolve/auxiliary/fake_matches.rs
new file mode 100644
index 00000000000..6d42972cbac
--- /dev/null
+++ b/tests/ui/resolve/auxiliary/fake_matches.rs
@@ -0,0 +1,13 @@
+// Helper for test tests/ui/resolve/const-with-typo-in-pattern-binding-ice-135289.rs
+
+//@ edition: 2018
+
+#[macro_export]
+macro_rules! assert_matches {
+    ( $e:expr , $($pat:pat)|+ ) => {
+        match $e {
+            $($pat)|+ => (),
+            _ => (),
+        }
+    };
+}
diff --git a/tests/ui/resolve/const-with-typo-in-pattern-binding-ice-135289.rs b/tests/ui/resolve/const-with-typo-in-pattern-binding-ice-135289.rs
new file mode 100644
index 00000000000..8267a9250ec
--- /dev/null
+++ b/tests/ui/resolve/const-with-typo-in-pattern-binding-ice-135289.rs
@@ -0,0 +1,17 @@
+// This is a non-regression test for issue 135289, where the "const with typo in pattern" diagnostic
+// caused an ICE when unexpectedly pretty printing a type for unreachable arms via a macro defined
+// in a dependency.
+
+#![warn(unreachable_patterns)] // needed to reproduce the ICE described in #135289
+
+//@ check-pass
+//@ aux-build: fake_matches.rs
+extern crate fake_matches;
+
+const _A: u64 = 0;
+pub fn f() -> u64 {
+    0
+}
+fn main() {
+    fake_matches::assert_matches!(f(), _non_existent);
+}
diff --git a/tests/ui/resolve/issue-3907-2.stderr b/tests/ui/resolve/issue-3907-2.stderr
index 7c47c5973e3..4ab72a42eb8 100644
--- a/tests/ui/resolve/issue-3907-2.stderr
+++ b/tests/ui/resolve/issue-3907-2.stderr
@@ -1,14 +1,15 @@
-error[E0038]: the trait `issue_3907::Foo` cannot be made into an object
+error[E0038]: the trait `issue_3907::Foo` is not dyn compatible
   --> $DIR/issue-3907-2.rs:11:12
    |
 LL | fn bar(_x: Foo) {}
-   |            ^^^ `issue_3907::Foo` cannot be made into an object
+   |            ^^^ `issue_3907::Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/auxiliary/issue-3907.rs:2:8
    |
 LL |     fn bar();
-   |        ^^^ the trait cannot be made into an object because associated function `bar` has no `self` parameter
+   |        ^^^ the trait is not dyn compatible because associated function `bar` has no `self` parameter
 
 error[E0277]: the size for values of type `(dyn issue_3907::Foo + 'static)` cannot be known at compilation time
   --> $DIR/issue-3907-2.rs:11:12
diff --git a/tests/ui/resolve/multiple_definitions_attribute_merging.stderr b/tests/ui/resolve/multiple_definitions_attribute_merging.stderr
index 804fa079bb9..ac6307c7a69 100644
--- a/tests/ui/resolve/multiple_definitions_attribute_merging.stderr
+++ b/tests/ui/resolve/multiple_definitions_attribute_merging.stderr
@@ -21,7 +21,7 @@ Box<dyn Any>
 query stack during panic:
 #0 [mir_built] building MIR for `<impl at $DIR/multiple_definitions_attribute_merging.rs:15:10: 15:19>::eq`
 #1 [check_unsafety] unsafety-checking `<impl at $DIR/multiple_definitions_attribute_merging.rs:15:10: 15:19>::eq`
-end of query stack
+... and 1 other queries... use `env RUST_BACKTRACE=1` to see the full query stack
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0428`.
diff --git a/tests/ui/resolve/proc_macro_generated_packed.stderr b/tests/ui/resolve/proc_macro_generated_packed.stderr
index a5a02c9c393..8b700595034 100644
--- a/tests/ui/resolve/proc_macro_generated_packed.stderr
+++ b/tests/ui/resolve/proc_macro_generated_packed.stderr
@@ -12,6 +12,6 @@ Box<dyn Any>
 query stack during panic:
 #0 [mir_built] building MIR for `<impl at $DIR/proc_macro_generated_packed.rs:15:10: 15:19>::eq`
 #1 [check_unsafety] unsafety-checking `<impl at $DIR/proc_macro_generated_packed.rs:15:10: 15:19>::eq`
-end of query stack
+... and 1 other queries... use `env RUST_BACKTRACE=1` to see the full query stack
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/resolve/resolve-issue-135614-assoc-const.import_trait_associated_functions.stderr b/tests/ui/resolve/resolve-issue-135614-assoc-const.import_trait_associated_functions.stderr
new file mode 100644
index 00000000000..b41fa1818e2
--- /dev/null
+++ b/tests/ui/resolve/resolve-issue-135614-assoc-const.import_trait_associated_functions.stderr
@@ -0,0 +1,19 @@
+error[E0005]: refutable pattern in local binding
+  --> $DIR/resolve-issue-135614-assoc-const.rs:21:9
+   |
+LL |     let DEFAULT: u32 = 0;
+   |         ^^^^^^^ pattern `1_u32..=u32::MAX` not covered
+LL |     const DEFAULT: u32 = 0;
+   |     ------------------ missing patterns are not covered because `DEFAULT` is interpreted as a constant pattern, not a new variable
+   |
+   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html
+   = note: the matched value is of type `u32`
+help: introduce a variable instead
+   |
+LL |     let DEFAULT_var: u32 = 0;
+   |         ~~~~~~~~~~~
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0005`.
diff --git a/tests/ui/resolve/resolve-issue-135614-assoc-const.normal.stderr b/tests/ui/resolve/resolve-issue-135614-assoc-const.normal.stderr
new file mode 100644
index 00000000000..908f5bdd897
--- /dev/null
+++ b/tests/ui/resolve/resolve-issue-135614-assoc-const.normal.stderr
@@ -0,0 +1,30 @@
+error[E0658]: `use` associated items of traits is unstable
+  --> $DIR/resolve-issue-135614-assoc-const.rs:6:5
+   |
+LL | use MyDefault::DEFAULT;
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #134691 <https://github.com/rust-lang/rust/issues/134691> for more information
+   = help: add `#![feature(import_trait_associated_functions)]` 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[E0005]: refutable pattern in local binding
+  --> $DIR/resolve-issue-135614-assoc-const.rs:21:9
+   |
+LL |     let DEFAULT: u32 = 0;
+   |         ^^^^^^^ pattern `1_u32..=u32::MAX` not covered
+LL |     const DEFAULT: u32 = 0;
+   |     ------------------ missing patterns are not covered because `DEFAULT` is interpreted as a constant pattern, not a new variable
+   |
+   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html
+   = note: the matched value is of type `u32`
+help: introduce a variable instead
+   |
+LL |     let DEFAULT_var: u32 = 0;
+   |         ~~~~~~~~~~~
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0005, E0658.
+For more information about an error, try `rustc --explain E0005`.
diff --git a/tests/ui/resolve/resolve-issue-135614-assoc-const.rs b/tests/ui/resolve/resolve-issue-135614-assoc-const.rs
new file mode 100644
index 00000000000..5a592922cd4
--- /dev/null
+++ b/tests/ui/resolve/resolve-issue-135614-assoc-const.rs
@@ -0,0 +1,30 @@
+//@ revisions: normal import_trait_associated_functions
+#![cfg_attr(import_trait_associated_functions, feature(import_trait_associated_functions))]
+
+// Makes sure that imported constant can be used in pattern bindings.
+
+use MyDefault::DEFAULT; //[normal]~ ERROR `use` associated items of traits is unstable
+
+trait MyDefault {
+    const DEFAULT: Self;
+}
+
+impl MyDefault for u32 {
+    const DEFAULT: u32 = 0;
+}
+
+impl MyDefault for () {
+    const DEFAULT: () = ();
+}
+
+fn foo(x: u32) -> u32 {
+    let DEFAULT: u32 = 0; //~ ERROR refutable pattern in local binding
+    const DEFAULT: u32 = 0;
+    if let DEFAULT = x { DEFAULT } else { 1 }
+}
+
+fn bar() {
+    let DEFAULT = ();
+}
+
+fn main() {}
diff --git a/tests/ui/resolve/resolve-issue-135614.normal.stderr b/tests/ui/resolve/resolve-issue-135614.normal.stderr
new file mode 100644
index 00000000000..a9adeb0848e
--- /dev/null
+++ b/tests/ui/resolve/resolve-issue-135614.normal.stderr
@@ -0,0 +1,13 @@
+error[E0658]: `use` associated items of traits is unstable
+  --> $DIR/resolve-issue-135614.rs:7:5
+   |
+LL | use A::b;
+   |     ^^^^
+   |
+   = note: see issue #134691 <https://github.com/rust-lang/rust/issues/134691> for more information
+   = help: add `#![feature(import_trait_associated_functions)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/resolve/resolve-issue-135614.rs b/tests/ui/resolve/resolve-issue-135614.rs
new file mode 100644
index 00000000000..fec9499365b
--- /dev/null
+++ b/tests/ui/resolve/resolve-issue-135614.rs
@@ -0,0 +1,15 @@
+//@ revisions: normal import_trait_associated_functions
+//@[import_trait_associated_functions] check-pass
+#![cfg_attr(import_trait_associated_functions, feature(import_trait_associated_functions))]
+
+// Makes sure that imported associated functions are shadowed by the local declarations.
+
+use A::b; //[normal]~ ERROR `use` associated items of traits is unstable
+
+trait A {
+    fn b() {}
+}
+
+fn main() {
+    let b: ();
+}
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.rs b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.rs
new file mode 100644
index 00000000000..2a7e730af16
--- /dev/null
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.rs
@@ -0,0 +1,12 @@
+#![feature(never_patterns)]
+#![allow(incomplete_features)]
+
+enum E { A }
+
+fn main() {
+    match E::A {
+        ! | //~ ERROR: a trailing `|` is not allowed in an or-pattern
+        //~^ ERROR: mismatched types
+        if true => {} //~ ERROR: a never pattern is always unreachable
+    }
+}
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.stderr
new file mode 100644
index 00000000000..26731e29ffc
--- /dev/null
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.stderr
@@ -0,0 +1,33 @@
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/ICE-130779-never-arm-no-oatherwise-block.rs:8:11
+   |
+LL |         ! |
+   |         - ^
+   |         |
+   |         while parsing this or-pattern starting here
+   |
+help: remove the `|`
+   |
+LL -         ! |
+LL +         !
+   |
+
+error: a never pattern is always unreachable
+  --> $DIR/ICE-130779-never-arm-no-oatherwise-block.rs:10:20
+   |
+LL |         if true => {}
+   |                    ^^
+   |                    |
+   |                    this will never be executed
+   |                    help: remove this expression
+
+error: mismatched types
+  --> $DIR/ICE-130779-never-arm-no-oatherwise-block.rs:8:9
+   |
+LL |         ! |
+   |         ^ a never pattern must be used on an uninhabited type
+   |
+   = note: the matched value is of type `E`
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.rs b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.rs
new file mode 100644
index 00000000000..4f52f6ee4bd
--- /dev/null
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.rs
@@ -0,0 +1,16 @@
+#![feature(never_type)]
+#![feature(never_patterns)]
+#![allow(incomplete_features)]
+
+enum Void {}
+
+fn foo(x: Void) {
+    loop {
+        match x {
+            (!|!) if false => {} //~ ERROR a never pattern is always unreachable
+            _ => {}
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.stderr
new file mode 100644
index 00000000000..cc451fed318
--- /dev/null
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.stderr
@@ -0,0 +1,11 @@
+error: a never pattern is always unreachable
+  --> $DIR/ICE-133063-never-arm-no-otherwise-block.rs:10:31
+   |
+LL |             (!|!) if false => {}
+   |                               ^^
+   |                               |
+   |                               this will never be executed
+   |                               help: remove this expression
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.rs b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.rs
new file mode 100644
index 00000000000..bca2ab56570
--- /dev/null
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.rs
@@ -0,0 +1,14 @@
+#![feature(never_type)]
+#![feature(never_patterns)]
+#![allow(incomplete_features)]
+
+enum Void {}
+
+fn foo(x: Void) {
+    match x {
+        (!|!) if true => {} //~ ERROR a never pattern is always unreachable
+        (!|!) if true => {} //~ ERROR a never pattern is always unreachable
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.stderr
new file mode 100644
index 00000000000..5da9642dc19
--- /dev/null
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.stderr
@@ -0,0 +1,20 @@
+error: a never pattern is always unreachable
+  --> $DIR/ICE-133117-duplicate-never-arm.rs:9:26
+   |
+LL |         (!|!) if true => {}
+   |                          ^^
+   |                          |
+   |                          this will never be executed
+   |                          help: remove this expression
+
+error: a never pattern is always unreachable
+  --> $DIR/ICE-133117-duplicate-never-arm.rs:10:26
+   |
+LL |         (!|!) if true => {}
+   |                          ^^
+   |                          |
+   |                          this will never be executed
+   |                          help: remove this expression
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.rs b/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.rs
deleted file mode 100644
index f0e111b578f..00000000000
--- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-#![feature(start)]
-
-#[start]
-#[track_caller] //~ ERROR `#[start]` function is not allowed to be `#[track_caller]`
-fn start(_argc: isize, _argv: *const *const u8) -> isize {
-    panic!("{}: oh no", std::panic::Location::caller());
-}
diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.stderr b/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.stderr
deleted file mode 100644
index 2738444f21f..00000000000
--- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-error: `#[start]` function is not allowed to be `#[track_caller]`
-  --> $DIR/error-with-start.rs:4:1
-   |
-LL | #[track_caller]
-   | ^^^^^^^^^^^^^^^
-LL | fn start(_argc: isize, _argv: *const *const u8) -> isize {
-   | -------------------------------------------------------- `#[start]` function is not allowed to be `#[track_caller]`
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.rs
deleted file mode 100644
index 6aa8f6fd821..00000000000
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ only-x86_64
-
-#![feature(start)]
-#![feature(target_feature_11)]
-
-#[start]
-#[target_feature(enable = "avx2")]
-//~^ ERROR `#[start]` function is not allowed to have `#[target_feature]`
-fn start(_argc: isize, _argv: *const *const u8) -> isize { 0 }
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.stderr
deleted file mode 100644
index d0a67c4f6a8..00000000000
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error: `#[start]` function is not allowed to have `#[target_feature]`
-  --> $DIR/issue-108645-target-feature-on-start.rs:7:1
-   |
-LL | #[target_feature(enable = "avx2")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-LL |
-LL | fn start(_argc: isize, _argv: *const *const u8) -> isize { 0 }
-   | -------------------------------------------------------- `#[start]` function is not allowed to have `#[target_feature]`
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/runtime/native-print-no-runtime.rs b/tests/ui/runtime/native-print-no-runtime.rs
deleted file mode 100644
index f0ed7d97b2c..00000000000
--- a/tests/ui/runtime/native-print-no-runtime.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ run-pass
-
-#![feature(start)]
-
-#[start]
-pub fn main(_: isize, _: *const *const u8) -> isize {
-    println!("hello");
-    0
-}
diff --git a/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs b/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs
index 229408fb724..f3f9ce0bd87 100644
--- a/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs
+++ b/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs
@@ -4,15 +4,16 @@
 //@ compile-flags: -Cpanic=abort
 //@ no-prefer-dynamic so panic=abort works
 
-#![feature(start, rustc_private)]
+#![feature(rustc_private)]
+#![no_main]
 
 extern crate libc;
 
-// Use #[start] so we don't have a runtime that messes with SIGPIPE.
-#[start]
-fn start(argc: isize, argv: *const *const u8) -> isize {
+// Use no_main so we don't have a runtime that messes with SIGPIPE.
+#[no_mangle]
+extern "C" fn main(argc: core::ffi::c_int, argv: *const *const u8) -> core::ffi::c_int {
     assert_eq!(argc, 2, "Must pass SIG_IGN or SIG_DFL as first arg");
-    let arg1 = unsafe { std::ffi::CStr::from_ptr(*argv.offset(1) as *const libc::c_char) }
+    let arg1 = unsafe { core::ffi::CStr::from_ptr(*argv.offset(1) as *const libc::c_char) }
         .to_str()
         .unwrap();
 
@@ -23,8 +24,8 @@ fn start(argc: isize, argv: *const *const u8) -> isize {
     };
 
     let actual = unsafe {
-        let mut actual: libc::sigaction = std::mem::zeroed();
-        libc::sigaction(libc::SIGPIPE, std::ptr::null(), &mut actual);
+        let mut actual: libc::sigaction = core::mem::zeroed();
+        libc::sigaction(libc::SIGPIPE, core::ptr::null(), &mut actual);
         #[cfg(not(target_os = "aix"))]
         {
             actual.sa_sigaction
diff --git a/tests/ui/runtime/running-with-no-runtime.rs b/tests/ui/runtime/running-with-no-runtime.rs
index 695025b3859..5c219b6feda 100644
--- a/tests/ui/runtime/running-with-no-runtime.rs
+++ b/tests/ui/runtime/running-with-no-runtime.rs
@@ -2,15 +2,15 @@
 //@ ignore-wasm32 spawning processes is not supported
 //@ ignore-sgx no processes
 
-#![feature(start)]
+#![no_main]
 
 use std::ffi::CStr;
 use std::process::{Command, Output};
 use std::panic;
 use std::str;
 
-#[start]
-fn start(argc: isize, argv: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(argc: core::ffi::c_int, argv: *const *const u8) -> core::ffi::c_int {
     if argc > 1 {
         unsafe {
             match **argv.offset(1) as char {
diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed
index 8b179f7ef93..cba3d7f1f9f 100644
--- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed
+++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed
@@ -40,6 +40,15 @@ macro_rules! meta2 {
     }
 }
 
+macro_rules! with_cfg_attr {
+    () => {
+        #[cfg_attr(all(), unsafe(link_section = ".custom_section"))]
+        //~^ ERROR: unsafe attribute used without unsafe
+        //~| WARN this is accepted in the current edition
+        pub extern "C" fn abc() {}
+    };
+}
+
 tt!([unsafe(no_mangle)]);
 //~^ ERROR: unsafe attribute used without unsafe
 //~| WARN this is accepted in the current edition
@@ -52,6 +61,8 @@ meta2!(unsafe(export_name = "baw"));
 //~| WARN this is accepted in the current edition
 ident2!(export_name, "bars");
 
+with_cfg_attr!();
+
 #[unsafe(no_mangle)]
 //~^ ERROR: unsafe attribute used without unsafe
 //~| WARN this is accepted in the current edition
diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs
index 34e5a6b96e3..4bbf9b25de5 100644
--- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs
+++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs
@@ -40,6 +40,15 @@ macro_rules! meta2 {
     }
 }
 
+macro_rules! with_cfg_attr {
+    () => {
+        #[cfg_attr(all(), link_section = ".custom_section")]
+        //~^ ERROR: unsafe attribute used without unsafe
+        //~| WARN this is accepted in the current edition
+        pub extern "C" fn abc() {}
+    };
+}
+
 tt!([no_mangle]);
 //~^ ERROR: unsafe attribute used without unsafe
 //~| WARN this is accepted in the current edition
@@ -52,6 +61,8 @@ meta2!(export_name = "baw");
 //~| WARN this is accepted in the current edition
 ident2!(export_name, "bars");
 
+with_cfg_attr!();
+
 #[no_mangle]
 //~^ ERROR: unsafe attribute used without unsafe
 //~| WARN this is accepted in the current edition
diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr
index 87330d2693d..15a48fb7159 100644
--- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr
+++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr
@@ -1,5 +1,5 @@
 error: unsafe attribute used without unsafe
-  --> $DIR/unsafe-attributes-fix.rs:43:6
+  --> $DIR/unsafe-attributes-fix.rs:52:6
    |
 LL | tt!([no_mangle]);
    |      ^^^^^^^^^ usage of unsafe attribute
@@ -34,7 +34,7 @@ LL |         #[unsafe($e)]
    |           +++++++  +
 
 error: unsafe attribute used without unsafe
-  --> $DIR/unsafe-attributes-fix.rs:47:7
+  --> $DIR/unsafe-attributes-fix.rs:56:7
    |
 LL | meta!(no_mangle);
    |       ^^^^^^^^^ usage of unsafe attribute
@@ -47,7 +47,7 @@ LL | meta!(unsafe(no_mangle));
    |       +++++++         +
 
 error: unsafe attribute used without unsafe
-  --> $DIR/unsafe-attributes-fix.rs:50:8
+  --> $DIR/unsafe-attributes-fix.rs:59:8
    |
 LL | meta2!(export_name = "baw");
    |        ^^^^^^^^^^^ usage of unsafe attribute
@@ -77,7 +77,24 @@ LL |         #[unsafe($e = $l)]
    |           +++++++       +
 
 error: unsafe attribute used without unsafe
-  --> $DIR/unsafe-attributes-fix.rs:55:3
+  --> $DIR/unsafe-attributes-fix.rs:45:27
+   |
+LL |         #[cfg_attr(all(), link_section = ".custom_section")]
+   |                           ^^^^^^^^^^^^ usage of unsafe attribute
+...
+LL | with_cfg_attr!();
+   | ---------------- in this macro invocation
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-attributes.html>
+   = note: this error originates in the macro `with_cfg_attr` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: wrap the attribute in `unsafe(...)`
+   |
+LL |         #[cfg_attr(all(), unsafe(link_section = ".custom_section"))]
+   |                           +++++++                                +
+
+error: unsafe attribute used without unsafe
+  --> $DIR/unsafe-attributes-fix.rs:66:3
    |
 LL | #[no_mangle]
    |   ^^^^^^^^^ usage of unsafe attribute
@@ -89,5 +106,5 @@ help: wrap the attribute in `unsafe(...)`
 LL | #[unsafe(no_mangle)]
    |   +++++++         +
 
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/tests/ui/sanitizer/memory-eager.rs b/tests/ui/sanitizer/memory-eager.rs
index 9e7889fa1bc..532d7b308f6 100644
--- a/tests/ui/sanitizer/memory-eager.rs
+++ b/tests/ui/sanitizer/memory-eager.rs
@@ -15,7 +15,7 @@
 // since it will be linked with an uninstrumented version of it.
 
 #![feature(core_intrinsics)]
-#![feature(start)]
+#![no_main]
 
 use std::hint::black_box;
 use std::mem::MaybeUninit;
@@ -29,8 +29,8 @@ fn random() -> char {
     black_box(r)
 }
 
-#[start]
-fn main(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(_argc: std::ffi::c_int, _argv: *const *const u8) -> std::ffi::c_int {
     random();
     0
 }
diff --git a/tests/ui/sanitizer/memory-passing.rs b/tests/ui/sanitizer/memory-passing.rs
index c8ab64bfaf8..96a4cd909c7 100644
--- a/tests/ui/sanitizer/memory-passing.rs
+++ b/tests/ui/sanitizer/memory-passing.rs
@@ -12,8 +12,8 @@
 // since it will be linked with an uninstrumented version of it.
 
 #![feature(core_intrinsics)]
-#![feature(start)]
 #![allow(invalid_value)]
+#![no_main]
 
 use std::hint::black_box;
 
@@ -25,8 +25,8 @@ fn calling_black_box_on_zst_ok() {
     black_box(zst);
 }
 
-#[start]
-fn main(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(_argc: std::ffi::c_int, _argv: *const *const u8) -> std::ffi::c_int {
     calling_black_box_on_zst_ok();
     0
 }
diff --git a/tests/ui/sanitizer/memory.rs b/tests/ui/sanitizer/memory.rs
index bd2d6771749..a91fefe4d16 100644
--- a/tests/ui/sanitizer/memory.rs
+++ b/tests/ui/sanitizer/memory.rs
@@ -15,8 +15,8 @@
 // since it will be linked with an uninstrumented version of it.
 
 #![feature(core_intrinsics)]
-#![feature(start)]
 #![allow(invalid_value)]
+#![no_main]
 
 use std::hint::black_box;
 use std::mem::MaybeUninit;
@@ -39,8 +39,8 @@ fn xor(a: &[isize]) -> isize {
     s
 }
 
-#[start]
-fn main(_: isize, _: *const *const u8) -> isize {
+#[no_mangle]
+extern "C" fn main(_argc: std::ffi::c_int, _argv: *const *const u8) -> std::ffi::c_int {
     let r = black_box(random as fn() -> [isize; 32])();
-    xor(&r)
+    xor(&r) as std::ffi::c_int
 }
diff --git a/tests/ui/self/arbitrary-self-types-dyn-incompatible.curr.stderr b/tests/ui/self/arbitrary-self-types-dyn-incompatible.curr.stderr
index 2eb7597d5c1..3e018995ba5 100644
--- a/tests/ui/self/arbitrary-self-types-dyn-incompatible.curr.stderr
+++ b/tests/ui/self/arbitrary-self-types-dyn-incompatible.curr.stderr
@@ -1,38 +1,40 @@
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/arbitrary-self-types-dyn-incompatible.rs:33:32
    |
 LL |     fn foo(self: &Rc<Self>) -> usize;
    |                  --------- help: consider changing method `foo`'s `self` parameter to be `&self`: `&Self`
 ...
 LL |     let x = Rc::new(5usize) as Rc<dyn Foo>;
-   |                                ^^^^^^^^^^^ `Foo` cannot be made into an object
+   |                                ^^^^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/arbitrary-self-types-dyn-incompatible.rs:8:18
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn foo(self: &Rc<Self>) -> usize;
    |                  ^^^^^^^^^ ...because method `foo`'s `self` parameter cannot be dispatched on
-   = help: only type `usize` implements the trait, consider using it directly instead
+   = help: only type `usize` implements `Foo`; consider using it directly instead.
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/arbitrary-self-types-dyn-incompatible.rs:33:13
    |
 LL |     fn foo(self: &Rc<Self>) -> usize;
    |                  --------- help: consider changing method `foo`'s `self` parameter to be `&self`: `&Self`
 ...
 LL |     let x = Rc::new(5usize) as Rc<dyn Foo>;
-   |             ^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |             ^^^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/arbitrary-self-types-dyn-incompatible.rs:8:18
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn foo(self: &Rc<Self>) -> usize;
    |                  ^^^^^^^^^ ...because method `foo`'s `self` parameter cannot be dispatched on
-   = help: only type `usize` implements the trait, consider using it directly instead
+   = help: only type `usize` implements `Foo`; consider using it directly instead.
    = note: required for the cast from `Rc<usize>` to `Rc<dyn Foo>`
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr b/tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr
index 02af692c4a3..12c93d58537 100644
--- a/tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr
@@ -1,20 +1,21 @@
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/arbitrary-self-types-dyn-incompatible.rs:33:13
    |
 LL |     fn foo(self: &Rc<Self>) -> usize;
    |                  --------- help: consider changing method `foo`'s `self` parameter to be `&self`: `&Self`
 ...
 LL |     let x = Rc::new(5usize) as Rc<dyn Foo>;
-   |             ^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |             ^^^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/arbitrary-self-types-dyn-incompatible.rs:8:18
    |
 LL | trait Foo {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn foo(self: &Rc<Self>) -> usize;
    |                  ^^^^^^^^^ ...because method `foo`'s `self` parameter cannot be dispatched on
-   = help: only type `usize` implements the trait, consider using it directly instead
+   = help: only type `usize` implements `Foo`; consider using it directly instead.
    = note: required for the cast from `Rc<usize>` to `Rc<dyn Foo>`
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.stderr b/tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.stderr
index 0a5f58288fa..0f2006e932b 100644
--- a/tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.stderr
+++ b/tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.stderr
@@ -4,7 +4,10 @@ error: `foobar` is not yet stable as a const fn
 LL |     foobar();
    |     ^^^^^^^^
    |
-   = help: add `#![feature(const_foobar)]` to the crate attributes to enable
+help: add `#![feature(const_foobar)]` to the crate attributes to enable
+   |
+LL + #![feature(const_foobar)]
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/stable-mir-print/operands.stdout b/tests/ui/stable-mir-print/operands.stdout
index c3b1151ae24..3c27878b3cf 100644
--- a/tests/ui/stable-mir-print/operands.stdout
+++ b/tests/ui/stable-mir-print/operands.stdout
@@ -5,183 +5,187 @@ fn operands(_1: u8) -> () {
     let  _2: [u8; 10];
     let  _3: u8;
     let  _4: usize;
-    let mut _5: bool;
-    let  _6: u8;
-    let  _7: usize;
-    let mut _8: (usize, bool);
-    let mut _9: bool;
-    let mut _10: (&u8, &u8);
-    let mut _11: &u8;
-    let mut _12: &u8;
-    let  _13: &u8;
-    let  _14: &u8;
-    let mut _15: bool;
-    let mut _16: u8;
-    let mut _17: u8;
-    let  _18: core::panicking::AssertKind;
-    let  _19: !;
-    let mut _20: Option<Arguments<'_>>;
-    let  _21: &u8;
-    let  _22: u8;
-    let mut _23: (&u8, &u8);
-    let mut _24: &u8;
-    let mut _25: &u8;
-    let  _26: &u8;
-    let  _27: &u8;
-    let mut _28: bool;
-    let mut _29: u8;
-    let mut _30: u8;
-    let  _31: core::panicking::AssertKind;
-    let  _32: !;
-    let mut _33: Option<Arguments<'_>>;
-    let  _34: (u8, u8);
-    let  _35: u8;
-    let  _36: u8;
-    let mut _37: (&u8, &u8);
-    let mut _38: &u8;
-    let mut _39: &u8;
-    let  _40: &u8;
-    let  _41: &u8;
-    let mut _42: bool;
-    let mut _43: u8;
-    let mut _44: u8;
-    let  _45: core::panicking::AssertKind;
-    let  _46: !;
-    let mut _47: Option<Arguments<'_>>;
-    let  _48: usize;
-    let mut _49: &[u8];
-    let mut _50: &[u8; 10];
-    let  _51: usize;
-    let  _52: &usize;
-    let mut _53: (&usize, &usize);
-    let mut _54: &usize;
-    let mut _55: &usize;
-    let  _56: &usize;
-    let  _57: &usize;
-    let mut _58: bool;
-    let mut _59: usize;
-    let mut _60: usize;
-    let  _61: core::panicking::AssertKind;
-    let  _62: !;
-    let mut _63: Option<Arguments<'_>>;
+    let mut _5: usize;
+    let mut _6: bool;
+    let  _7: u8;
+    let  _8: usize;
+    let mut _9: (usize, bool);
+    let mut _10: usize;
+    let mut _11: bool;
+    let mut _12: (&u8, &u8);
+    let mut _13: &u8;
+    let mut _14: &u8;
+    let  _15: &u8;
+    let  _16: &u8;
+    let mut _17: bool;
+    let mut _18: u8;
+    let mut _19: u8;
+    let  _20: core::panicking::AssertKind;
+    let  _21: !;
+    let mut _22: Option<Arguments<'_>>;
+    let  _23: &u8;
+    let  _24: u8;
+    let mut _25: (&u8, &u8);
+    let mut _26: &u8;
+    let mut _27: &u8;
+    let  _28: &u8;
+    let  _29: &u8;
+    let mut _30: bool;
+    let mut _31: u8;
+    let mut _32: u8;
+    let  _33: core::panicking::AssertKind;
+    let  _34: !;
+    let mut _35: Option<Arguments<'_>>;
+    let  _36: (u8, u8);
+    let  _37: u8;
+    let  _38: u8;
+    let mut _39: (&u8, &u8);
+    let mut _40: &u8;
+    let mut _41: &u8;
+    let  _42: &u8;
+    let  _43: &u8;
+    let mut _44: bool;
+    let mut _45: u8;
+    let mut _46: u8;
+    let  _47: core::panicking::AssertKind;
+    let  _48: !;
+    let mut _49: Option<Arguments<'_>>;
+    let  _50: usize;
+    let mut _51: &[u8];
+    let mut _52: &[u8; 10];
+    let  _53: usize;
+    let  _54: &usize;
+    let mut _55: (&usize, &usize);
+    let mut _56: &usize;
+    let mut _57: &usize;
+    let  _58: &usize;
+    let  _59: &usize;
+    let mut _60: bool;
+    let mut _61: usize;
+    let mut _62: usize;
+    let  _63: core::panicking::AssertKind;
+    let  _64: !;
+    let mut _65: Option<Arguments<'_>>;
     debug val => _1;
     debug array => _2;
     debug first => _3;
-    debug last => _6;
-    debug left_val => _13;
-    debug right_val => _14;
-    debug kind => _18;
-    debug reference => _21;
-    debug dereferenced => _22;
-    debug left_val => _26;
-    debug right_val => _27;
-    debug kind => _31;
-    debug tuple => _34;
-    debug first_again => _35;
-    debug first_again_again => _36;
-    debug left_val => _40;
-    debug right_val => _41;
-    debug kind => _45;
-    debug length => _48;
-    debug size_of => _51;
-    debug left_val => _56;
-    debug right_val => _57;
-    debug kind => _61;
+    debug last => _7;
+    debug left_val => _15;
+    debug right_val => _16;
+    debug kind => _20;
+    debug reference => _23;
+    debug dereferenced => _24;
+    debug left_val => _28;
+    debug right_val => _29;
+    debug kind => _33;
+    debug tuple => _36;
+    debug first_again => _37;
+    debug first_again_again => _38;
+    debug left_val => _42;
+    debug right_val => _43;
+    debug kind => _47;
+    debug length => _50;
+    debug size_of => _53;
+    debug left_val => _58;
+    debug right_val => _59;
+    debug kind => _63;
     bb0: {
         _2 = [_1; 10];
         _4 = 0_usize;
-        _5 = Lt(_4, 10_usize);
-        assert(move _5, "index out of bounds: the length is {} but the index is {}", 10_usize, _4) -> [success: bb1, unwind unreachable];
+        _5 = 10_usize;
+        _6 = Lt(_4, _5);
+        assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable];
     }
     bb1: {
         _3 = _2[_4];
-        _8 = CheckedSub(10_usize, 1_usize);
-        assert(!move (_8.1: bool), "attempt to compute `{} - {}`, which would overflow", 10_usize, 1_usize) -> [success: bb2, unwind unreachable];
+        _9 = CheckedSub(10_usize, 1_usize);
+        assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", 10_usize, 1_usize) -> [success: bb2, unwind unreachable];
     }
     bb2: {
-        _7 = move (_8.0: usize);
-        _9 = Lt(_7, 10_usize);
-        assert(move _9, "index out of bounds: the length is {} but the index is {}", 10_usize, _7) -> [success: bb3, unwind unreachable];
+        _8 = move (_9.0: usize);
+        _10 = 10_usize;
+        _11 = Lt(_8, _10);
+        assert(move _11, "index out of bounds: the length is {} but the index is {}", move _10, _8) -> [success: bb3, unwind unreachable];
     }
     bb3: {
-        _6 = _2[_7];
-        _11 = &_3;
-        _12 = &_6;
-        _10 = (move _11, move _12);
-        _13 = (_10.0: &u8);
-        _14 = (_10.1: &u8);
-        _16 = (*_13);
-        _17 = (*_14);
-        _15 = Eq(move _16, move _17);
-        switchInt(move _15) -> [0: bb5, otherwise: bb4];
+        _7 = _2[_8];
+        _13 = &_3;
+        _14 = &_7;
+        _12 = (move _13, move _14);
+        _15 = (_12.0: &u8);
+        _16 = (_12.1: &u8);
+        _18 = (*_15);
+        _19 = (*_16);
+        _17 = Eq(move _18, move _19);
+        switchInt(move _17) -> [0: bb5, otherwise: bb4];
     }
     bb4: {
-        _21 = &_3;
-        _22 = (*_21);
-        _24 = &_22;
-        _25 = &_3;
-        _23 = (move _24, move _25);
-        _26 = (_23.0: &u8);
-        _27 = (_23.1: &u8);
-        _29 = (*_26);
-        _30 = (*_27);
-        _28 = Eq(move _29, move _30);
-        switchInt(move _28) -> [0: bb7, otherwise: bb6];
+        _23 = &_3;
+        _24 = (*_23);
+        _26 = &_24;
+        _27 = &_3;
+        _25 = (move _26, move _27);
+        _28 = (_25.0: &u8);
+        _29 = (_25.1: &u8);
+        _31 = (*_28);
+        _32 = (*_29);
+        _30 = Eq(move _31, move _32);
+        switchInt(move _30) -> [0: bb7, otherwise: bb6];
     }
     bb5: {
-        _18 = core::panicking::AssertKind::Eq;
-        _20 = std::option::Option::None;
-        _19 = core::panicking::assert_failed::<u8, u8>(move _18, _13, _14, move _20) -> unwind unreachable;
+        _20 = core::panicking::AssertKind::Eq;
+        _22 = std::option::Option::None;
+        _21 = core::panicking::assert_failed::<u8, u8>(move _20, _15, _16, move _22) -> unwind unreachable;
     }
     bb6: {
-        _34 = (_3, _6);
-        _35 = (_34.0: u8);
-        _36 = (_34.0: u8);
-        _38 = &_35;
-        _39 = &_36;
-        _37 = (move _38, move _39);
-        _40 = (_37.0: &u8);
-        _41 = (_37.1: &u8);
-        _43 = (*_40);
-        _44 = (*_41);
-        _42 = Eq(move _43, move _44);
-        switchInt(move _42) -> [0: bb9, otherwise: bb8];
+        _36 = (_3, _7);
+        _37 = (_36.0: u8);
+        _38 = (_36.0: u8);
+        _40 = &_37;
+        _41 = &_38;
+        _39 = (move _40, move _41);
+        _42 = (_39.0: &u8);
+        _43 = (_39.1: &u8);
+        _45 = (*_42);
+        _46 = (*_43);
+        _44 = Eq(move _45, move _46);
+        switchInt(move _44) -> [0: bb9, otherwise: bb8];
     }
     bb7: {
-        _31 = core::panicking::AssertKind::Eq;
-        _33 = std::option::Option::None;
-        _32 = core::panicking::assert_failed::<u8, u8>(move _31, _26, _27, move _33) -> unwind unreachable;
+        _33 = core::panicking::AssertKind::Eq;
+        _35 = std::option::Option::None;
+        _34 = core::panicking::assert_failed::<u8, u8>(move _33, _28, _29, move _35) -> unwind unreachable;
     }
     bb8: {
-        _50 = &_2;
-        _49 = move _50 as &[u8];
-        _48 = PtrMetadata(move _49);
-        _52 = &_48;
-        _51 = std::mem::size_of_val::<usize>(_52) -> [return: bb10, unwind unreachable];
+        _52 = &_2;
+        _51 = move _52 as &[u8];
+        _50 = PtrMetadata(move _51);
+        _54 = &_50;
+        _53 = std::mem::size_of_val::<usize>(_54) -> [return: bb10, unwind unreachable];
     }
     bb9: {
-        _45 = core::panicking::AssertKind::Eq;
-        _47 = std::option::Option::None;
-        _46 = core::panicking::assert_failed::<u8, u8>(move _45, _40, _41, move _47) -> unwind unreachable;
+        _47 = core::panicking::AssertKind::Eq;
+        _49 = std::option::Option::None;
+        _48 = core::panicking::assert_failed::<u8, u8>(move _47, _42, _43, move _49) -> unwind unreachable;
     }
     bb10: {
-        _54 = &_48;
-        _55 = &_51;
-        _53 = (move _54, move _55);
-        _56 = (_53.0: &usize);
-        _57 = (_53.1: &usize);
-        _59 = (*_56);
-        _60 = (*_57);
-        _58 = Eq(move _59, move _60);
-        switchInt(move _58) -> [0: bb12, otherwise: bb11];
+        _56 = &_50;
+        _57 = &_53;
+        _55 = (move _56, move _57);
+        _58 = (_55.0: &usize);
+        _59 = (_55.1: &usize);
+        _61 = (*_58);
+        _62 = (*_59);
+        _60 = Eq(move _61, move _62);
+        switchInt(move _60) -> [0: bb12, otherwise: bb11];
     }
     bb11: {
         return;
     }
     bb12: {
-        _61 = core::panicking::AssertKind::Eq;
-        _63 = std::option::Option::None;
-        _62 = core::panicking::assert_failed::<usize, usize>(move _61, _56, _57, move _63) -> unwind unreachable;
+        _63 = core::panicking::AssertKind::Eq;
+        _65 = std::option::Option::None;
+        _64 = core::panicking::assert_failed::<usize, usize>(move _63, _58, _59, move _65) -> unwind unreachable;
     }
 }
 fn operands::{constant#0}() -> usize {
diff --git a/tests/ui/statics/unsizing-wfcheck-issue-127299.rs b/tests/ui/statics/unsizing-wfcheck-issue-127299.rs
index cd15be54ec7..fd07937d90f 100644
--- a/tests/ui/statics/unsizing-wfcheck-issue-127299.rs
+++ b/tests/ui/statics/unsizing-wfcheck-issue-127299.rs
@@ -6,12 +6,12 @@ trait Qux {
 
 pub struct Lint {
     pub desc: &'static dyn Qux,
-    //~^ ERROR cannot be made into an object
+    //~^ ERROR is not dyn compatible
 }
 
 static FOO: &Lint = &Lint { desc: "desc" };
 //~^ ERROR cannot be shared between threads safely
-//~| ERROR cannot be made into an object
-//~| ERROR cannot be made into an object
+//~| ERROR is not dyn compatible
+//~| ERROR is not dyn compatible
 
 fn main() {}
diff --git a/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr b/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr
index 35dd570e91f..08c744979f5 100644
--- a/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr
+++ b/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr
@@ -1,14 +1,15 @@
-error[E0038]: the trait `Qux` cannot be made into an object
+error[E0038]: the trait `Qux` is not dyn compatible
   --> $DIR/unsizing-wfcheck-issue-127299.rs:8:24
    |
 LL |     pub desc: &'static dyn Qux,
-   |                        ^^^^^^^ `Qux` cannot be made into an object
+   |                        ^^^^^^^ `Qux` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/unsizing-wfcheck-issue-127299.rs:4:8
    |
 LL | trait Qux {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn bar() -> i32;
    |        ^^^ ...because associated function `bar` has no `self` parameter
 help: consider turning `bar` into a method by giving it a `&self` argument
@@ -36,17 +37,18 @@ LL | pub struct Lint {
    = note: required because it appears within the type `&'static Lint`
    = note: shared static variables must have a type that implements `Sync`
 
-error[E0038]: the trait `Qux` cannot be made into an object
+error[E0038]: the trait `Qux` is not dyn compatible
   --> $DIR/unsizing-wfcheck-issue-127299.rs:12:35
    |
 LL | static FOO: &Lint = &Lint { desc: "desc" };
-   |                                   ^^^^^^ `Qux` cannot be made into an object
+   |                                   ^^^^^^ `Qux` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/unsizing-wfcheck-issue-127299.rs:4:8
    |
 LL | trait Qux {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn bar() -> i32;
    |        ^^^ ...because associated function `bar` has no `self` parameter
    = note: required for the cast from `&'static str` to `&'static (dyn Qux + 'static)`
@@ -59,17 +61,18 @@ help: alternatively, consider constraining `bar` so it does not apply to trait o
 LL |     fn bar() -> i32 where Self: Sized;
    |                     +++++++++++++++++
 
-error[E0038]: the trait `Qux` cannot be made into an object
+error[E0038]: the trait `Qux` is not dyn compatible
   --> $DIR/unsizing-wfcheck-issue-127299.rs:12:35
    |
 LL | static FOO: &Lint = &Lint { desc: "desc" };
-   |                                   ^^^^^^ `Qux` cannot be made into an object
+   |                                   ^^^^^^ `Qux` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/unsizing-wfcheck-issue-127299.rs:4:8
    |
 LL | trait Qux {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn bar() -> i32;
    |        ^^^ ...because associated function `bar` has no `self` parameter
 help: consider turning `bar` into a method by giving it a `&self` argument
diff --git a/tests/ui/structs/default-field-values/empty-struct.rs b/tests/ui/structs/default-field-values/empty-struct.rs
new file mode 100644
index 00000000000..c9cb861ae27
--- /dev/null
+++ b/tests/ui/structs/default-field-values/empty-struct.rs
@@ -0,0 +1,21 @@
+#![feature(default_field_values)]
+
+// If an API wants users to always use `..` even if they specify all the fields, they should use a
+// sentinel field. As of now, that field can't be made private so it is only constructable with this
+// syntax, but this might change in the future.
+
+struct A {}
+struct B();
+struct C;
+struct D {
+    x: i32,
+}
+struct E(i32);
+
+fn main() {
+    let _ = A { .. }; //~ ERROR has no fields
+    let _ = B { .. }; //~ ERROR has no fields
+    let _ = C { .. }; //~ ERROR has no fields
+    let _ = D { x: 0, .. };
+    let _ = E { 0: 0, .. };
+}
diff --git a/tests/ui/structs/default-field-values/empty-struct.stderr b/tests/ui/structs/default-field-values/empty-struct.stderr
new file mode 100644
index 00000000000..079e83415b4
--- /dev/null
+++ b/tests/ui/structs/default-field-values/empty-struct.stderr
@@ -0,0 +1,26 @@
+error: `A` has no fields, `..` needs at least one default field in the struct definition
+  --> $DIR/empty-struct.rs:16:17
+   |
+LL |     let _ = A { .. };
+   |             -   ^^
+   |             |
+   |             this type has no fields
+
+error: `B` has no fields, `..` needs at least one default field in the struct definition
+  --> $DIR/empty-struct.rs:17:17
+   |
+LL |     let _ = B { .. };
+   |             -   ^^
+   |             |
+   |             this type has no fields
+
+error: `C` has no fields, `..` needs at least one default field in the struct definition
+  --> $DIR/empty-struct.rs:18:17
+   |
+LL |     let _ = C { .. };
+   |             -   ^^
+   |             |
+   |             this type has no fields
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/structs/default-field-values/non-exhaustive-ctor.disabled.stderr b/tests/ui/structs/default-field-values/non-exhaustive-ctor.disabled.stderr
new file mode 100644
index 00000000000..63793425657
--- /dev/null
+++ b/tests/ui/structs/default-field-values/non-exhaustive-ctor.disabled.stderr
@@ -0,0 +1,86 @@
+error[E0658]: default values on fields are experimental
+  --> $DIR/non-exhaustive-ctor.rs:9:22
+   |
+LL |         pub field: () = (),
+   |                      ^^^^^
+   |
+   = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information
+   = help: add `#![feature(default_field_values)]` 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]: default values on fields are experimental
+  --> $DIR/non-exhaustive-ctor.rs:11:25
+   |
+LL |         pub field1: Priv = Priv,
+   |                         ^^^^^^^
+   |
+   = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information
+   = help: add `#![feature(default_field_values)]` 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]: default values on fields are experimental
+  --> $DIR/non-exhaustive-ctor.rs:13:25
+   |
+LL |         pub field2: Priv = Priv,
+   |                         ^^^^^^^
+   |
+   = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information
+   = help: add `#![feature(default_field_values)]` 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[E0797]: base expression required after `..`
+  --> $DIR/non-exhaustive-ctor.rs:20:19
+   |
+LL |     let _ = S { .. }; // ok
+   |                   ^
+   |
+help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+   |
+LL + #![feature(default_field_values)]
+   |
+help: add a base expression here
+   |
+LL |     let _ = S { ../* expr */ }; // ok
+   |                   ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/non-exhaustive-ctor.rs:22:30
+   |
+LL |     let _ = S { field: (), .. }; // ok
+   |                              ^
+   |
+help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+   |
+LL + #![feature(default_field_values)]
+   |
+help: add a base expression here
+   |
+LL |     let _ = S { field: (), ../* expr */ }; // ok
+   |                              ++++++++++
+
+error[E0063]: missing fields `field`, `field1` and `field2` in initializer of `S`
+  --> $DIR/non-exhaustive-ctor.rs:24:13
+   |
+LL |     let _ = S { };
+   |             ^ missing `field`, `field1` and `field2`
+   |
+help: all remaining fields have default values, if you added `#![feature(default_field_values)]` to your crate you could use those values with `..`
+   |
+LL |     let _ = S { .. };
+   |               ~~~~~~
+
+error[E0063]: missing fields `field1` and `field2` in initializer of `S`
+  --> $DIR/non-exhaustive-ctor.rs:26:13
+   |
+LL |     let _ = S { field: () };
+   |             ^ missing `field1` and `field2`
+   |
+help: all remaining fields have default values, if you added `#![feature(default_field_values)]` to your crate you could use those values with `..`
+   |
+LL |     let _ = S { field: (), .. };
+   |                          ++++
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0063, E0658, E0797.
+For more information about an error, try `rustc --explain E0063`.
diff --git a/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.fixed b/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.fixed
new file mode 100644
index 00000000000..7a371f993e8
--- /dev/null
+++ b/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.fixed
@@ -0,0 +1,28 @@
+//@ revisions: enabled disabled
+//@[enabled] run-rustfix
+#![allow(private_interfaces, dead_code)]
+#![cfg_attr(enabled, feature(default_field_values))]
+use m::S;
+
+mod m {
+    pub struct S {
+        pub field: () = (),
+        //[disabled]~^ ERROR default values on fields are experimental
+        pub field1: Priv = Priv,
+        //[disabled]~^ ERROR default values on fields are experimental
+        pub field2: Priv = Priv,
+        //[disabled]~^ ERROR default values on fields are experimental
+    }
+    struct Priv;
+}
+
+fn main() {
+    let _ = S { .. }; // ok
+    //[disabled]~^ ERROR base expression required after `..`
+    let _ = S { field: (), .. }; // ok
+    //[disabled]~^ ERROR base expression required after `..`
+    let _ = S { .. };
+    //~^ ERROR missing fields `field`, `field1` and `field2`
+    let _ = S { field: (), .. };
+    //~^ ERROR missing fields `field1` and `field2`
+}
diff --git a/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.stderr b/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.stderr
new file mode 100644
index 00000000000..6d035ebdc47
--- /dev/null
+++ b/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.stderr
@@ -0,0 +1,25 @@
+error[E0063]: missing fields `field`, `field1` and `field2` in initializer of `S`
+  --> $DIR/non-exhaustive-ctor.rs:24:13
+   |
+LL |     let _ = S { };
+   |             ^ missing `field`, `field1` and `field2`
+   |
+help: all remaining fields have default values, you can use those values with `..`
+   |
+LL |     let _ = S { .. };
+   |               ~~~~~~
+
+error[E0063]: missing fields `field1` and `field2` in initializer of `S`
+  --> $DIR/non-exhaustive-ctor.rs:26:13
+   |
+LL |     let _ = S { field: () };
+   |             ^ missing `field1` and `field2`
+   |
+help: all remaining fields have default values, you can use those values with `..`
+   |
+LL |     let _ = S { field: (), .. };
+   |                          ++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0063`.
diff --git a/tests/ui/structs/default-field-values/non-exhaustive-ctor.rs b/tests/ui/structs/default-field-values/non-exhaustive-ctor.rs
new file mode 100644
index 00000000000..b60b219f8bc
--- /dev/null
+++ b/tests/ui/structs/default-field-values/non-exhaustive-ctor.rs
@@ -0,0 +1,28 @@
+//@ revisions: enabled disabled
+//@[enabled] run-rustfix
+#![allow(private_interfaces, dead_code)]
+#![cfg_attr(enabled, feature(default_field_values))]
+use m::S;
+
+mod m {
+    pub struct S {
+        pub field: () = (),
+        //[disabled]~^ ERROR default values on fields are experimental
+        pub field1: Priv = Priv,
+        //[disabled]~^ ERROR default values on fields are experimental
+        pub field2: Priv = Priv,
+        //[disabled]~^ ERROR default values on fields are experimental
+    }
+    struct Priv;
+}
+
+fn main() {
+    let _ = S { .. }; // ok
+    //[disabled]~^ ERROR base expression required after `..`
+    let _ = S { field: (), .. }; // ok
+    //[disabled]~^ ERROR base expression required after `..`
+    let _ = S { };
+    //~^ ERROR missing fields `field`, `field1` and `field2`
+    let _ = S { field: () };
+    //~^ ERROR missing fields `field1` and `field2`
+}
diff --git a/tests/ui/structs/default-field-values/visibility.rs b/tests/ui/structs/default-field-values/visibility.rs
new file mode 100644
index 00000000000..ff1245551b0
--- /dev/null
+++ b/tests/ui/structs/default-field-values/visibility.rs
@@ -0,0 +1,42 @@
+#![feature(default_field_values)]
+pub mod foo {
+    #[derive(Default)]
+    pub struct Alpha {
+        beta: u8 = 42,
+        gamma: bool = true,
+    }
+}
+
+mod bar {
+    use crate::foo::Alpha;
+    fn baz() {
+        let _x = Alpha { .. };
+        //~^ ERROR fields `beta` and `gamma` of struct `Alpha` are private
+        let _x = Alpha {
+            beta: 0, //~ ERROR fields `beta` and `gamma` of struct `Alpha` are private
+            gamma: false,
+        };
+        let _x = Alpha {
+            beta: 0, //~ ERROR fields `beta` and `gamma` of struct `Alpha` are private
+            ..
+        };
+        let _x = Alpha { beta: 0, .. };
+        //~^ ERROR fields `beta` and `gamma` of struct `Alpha` are private
+        let _x = Alpha { beta: 0, ..Default::default() };
+        //~^ ERROR fields `beta` and `gamma` of struct `Alpha` are private
+    }
+}
+
+pub mod baz {
+    pub struct S {
+        x: i32 = 1,
+    }
+}
+fn main() {
+    let _a = baz::S {
+        .. //~ ERROR field `x` of struct `S` is private
+    };
+    let _b = baz::S {
+        x: 0, //~ ERROR field `x` of struct `S` is private
+    };
+}
diff --git a/tests/ui/structs/default-field-values/visibility.stderr b/tests/ui/structs/default-field-values/visibility.stderr
new file mode 100644
index 00000000000..38b96033252
--- /dev/null
+++ b/tests/ui/structs/default-field-values/visibility.stderr
@@ -0,0 +1,61 @@
+error[E0451]: field `x` of struct `S` is private
+  --> $DIR/visibility.rs:37:9
+   |
+LL |     let _a = baz::S {
+   |              ------ in this type
+LL |         ..
+   |         ^^ field `x` is private
+
+error[E0451]: field `x` of struct `S` is private
+  --> $DIR/visibility.rs:40:9
+   |
+LL |     let _b = baz::S {
+   |              ------ in this type
+LL |         x: 0,
+   |         ^ private field
+
+error[E0451]: fields `beta` and `gamma` of struct `Alpha` are private
+  --> $DIR/visibility.rs:13:26
+   |
+LL |         let _x = Alpha { .. };
+   |                          ^^ fields `beta` and `gamma` are private
+
+error[E0451]: fields `beta` and `gamma` of struct `Alpha` are private
+  --> $DIR/visibility.rs:16:13
+   |
+LL |         let _x = Alpha {
+   |                  ----- in this type
+LL |             beta: 0,
+   |             ^^^^ private field
+LL |             gamma: false,
+   |             ^^^^^ private field
+
+error[E0451]: fields `beta` and `gamma` of struct `Alpha` are private
+  --> $DIR/visibility.rs:20:13
+   |
+LL |         let _x = Alpha {
+   |                  ----- in this type
+LL |             beta: 0,
+   |             ^^^^^^^ private field
+LL |             ..
+   |             ^^ field `gamma` is private
+
+error[E0451]: fields `beta` and `gamma` of struct `Alpha` are private
+  --> $DIR/visibility.rs:23:26
+   |
+LL |         let _x = Alpha { beta: 0, .. };
+   |                          ^^^^^^^  ^^ field `gamma` is private
+   |                          |
+   |                          private field
+
+error[E0451]: fields `beta` and `gamma` of struct `Alpha` are private
+  --> $DIR/visibility.rs:25:26
+   |
+LL |         let _x = Alpha { beta: 0, ..Default::default() };
+   |                          ^^^^^^^    ^^^^^^^^^^^^^^^^^^ field `gamma` is private
+   |                          |
+   |                          private field
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0451`.
diff --git a/tests/ui/suggestions/dyn-incompatible-trait-references-self.rs b/tests/ui/suggestions/dyn-incompatible-trait-references-self.rs
index 4b3d5faba46..66b435247d4 100644
--- a/tests/ui/suggestions/dyn-incompatible-trait-references-self.rs
+++ b/tests/ui/suggestions/dyn-incompatible-trait-references-self.rs
@@ -6,10 +6,10 @@ trait Trait {
     //~| ERROR the size for values of type `Self` cannot be known
 }
 
-fn bar(x: &dyn Trait) {} //~ ERROR the trait `Trait` cannot be made into an object
+fn bar(x: &dyn Trait) {} //~ ERROR the trait `Trait` is not dyn compatible
 
 trait Other: Sized {}
 
-fn foo(x: &dyn Other) {} //~ ERROR the trait `Other` cannot be made into an object
+fn foo(x: &dyn Other) {} //~ ERROR the trait `Other` is not dyn compatible
 
 fn main() {}
diff --git a/tests/ui/suggestions/dyn-incompatible-trait-references-self.stderr b/tests/ui/suggestions/dyn-incompatible-trait-references-self.stderr
index 242c44abd9d..cb0e7fce910 100644
--- a/tests/ui/suggestions/dyn-incompatible-trait-references-self.stderr
+++ b/tests/ui/suggestions/dyn-incompatible-trait-references-self.stderr
@@ -1,14 +1,15 @@
-error[E0038]: the trait `Trait` cannot be made into an object
+error[E0038]: the trait `Trait` is not dyn compatible
   --> $DIR/dyn-incompatible-trait-references-self.rs:9:12
    |
 LL | fn bar(x: &dyn Trait) {}
-   |            ^^^^^^^^^ `Trait` cannot be made into an object
+   |            ^^^^^^^^^ `Trait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/dyn-incompatible-trait-references-self.rs:2:22
    |
 LL | trait Trait {
-   |       ----- this trait cannot be made into an object...
+   |       ----- this trait is not dyn compatible...
 LL |     fn baz(&self, _: Self) {}
    |                      ^^^^ ...because method `baz` references the `Self` type in this parameter
 LL |
@@ -17,19 +18,20 @@ LL |     fn bat(&self) -> Self {}
    = help: consider moving `baz` to another trait
    = help: consider moving `bat` to another trait
 
-error[E0038]: the trait `Other` cannot be made into an object
+error[E0038]: the trait `Other` is not dyn compatible
   --> $DIR/dyn-incompatible-trait-references-self.rs:13:12
    |
 LL | fn foo(x: &dyn Other) {}
-   |            ^^^^^^^^^ `Other` cannot be made into an object
+   |            ^^^^^^^^^ `Other` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/dyn-incompatible-trait-references-self.rs:11:14
    |
 LL | trait Other: Sized {}
    |       -----  ^^^^^ ...because it requires `Self: Sized`
    |       |
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
 
 error[E0277]: the size for values of type `Self` cannot be known at compilation time
   --> $DIR/dyn-incompatible-trait-references-self.rs:2:22
diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.rs b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.rs
index 4ab10f40eb6..747926c400a 100644
--- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.rs
+++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.rs
@@ -3,12 +3,12 @@
 trait A: Sized {
     fn f(a: dyn A) -> dyn A;
     //~^ ERROR associated item referring to unboxed trait object for its own trait
-    //~| ERROR the trait `A` cannot be made into an object
+    //~| ERROR the trait `A` is not dyn compatible
 }
 trait B {
     fn f(a: dyn B) -> dyn B;
     //~^ ERROR associated item referring to unboxed trait object for its own trait
-    //~| ERROR the trait `B` cannot be made into an object
+    //~| ERROR the trait `B` is not dyn compatible
 }
 trait C {
     fn f(&self, a: dyn C) -> dyn C;
diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr
index 5e0d1a14452..2efcad1e7bd 100644
--- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr
+++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr
@@ -11,19 +11,20 @@ help: you might have meant to use `Self` to refer to the implementing type
 LL |     fn f(a: Self) -> Self;
    |             ~~~~     ~~~~
 
-error[E0038]: the trait `A` cannot be made into an object
+error[E0038]: the trait `A` is not dyn compatible
   --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:4:13
    |
 LL |     fn f(a: dyn A) -> dyn A;
-   |             ^^^^^ `A` cannot be made into an object
+   |             ^^^^^ `A` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:3:10
    |
 LL | trait A: Sized {
    |       -  ^^^^^ ...because it requires `Self: Sized`
    |       |
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
 
 error: associated item referring to unboxed trait object for its own trait
   --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:9:13
@@ -38,17 +39,18 @@ help: you might have meant to use `Self` to refer to the implementing type
 LL |     fn f(a: Self) -> Self;
    |             ~~~~     ~~~~
 
-error[E0038]: the trait `B` cannot be made into an object
+error[E0038]: the trait `B` is not dyn compatible
   --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:9:13
    |
 LL |     fn f(a: dyn B) -> dyn B;
-   |             ^^^^^ `B` cannot be made into an object
+   |             ^^^^^ `B` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:9:8
    |
 LL | trait B {
-   |       - this trait cannot be made into an object...
+   |       - this trait is not dyn compatible...
 LL |     fn f(a: dyn B) -> dyn B;
    |        ^ ...because associated function `f` has no `self` parameter
 help: consider turning `f` into a method by giving it a `&self` argument
diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs
index 75f99075eb1..2893bbc8b71 100644
--- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs
+++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs
@@ -2,12 +2,12 @@
 trait A: Sized {
     fn f(a: A) -> A;
     //~^ ERROR associated item referring to unboxed trait object for its own trait
-    //~| ERROR the trait `A` cannot be made into an object
+    //~| ERROR the trait `A` is not dyn compatible
 }
 trait B {
     fn f(a: B) -> B;
     //~^ ERROR associated item referring to unboxed trait object for its own trait
-    //~| ERROR the trait `B` cannot be made into an object
+    //~| ERROR the trait `B` is not dyn compatible
 }
 trait C {
     fn f(&self, a: C) -> C;
diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr
index 93f6ea2b12e..ecb3ee9185f 100644
--- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr
+++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr
@@ -11,19 +11,20 @@ help: you might have meant to use `Self` to refer to the implementing type
 LL |     fn f(a: Self) -> Self;
    |             ~~~~     ~~~~
 
-error[E0038]: the trait `A` cannot be made into an object
+error[E0038]: the trait `A` is not dyn compatible
   --> $DIR/dyn-incompatible-trait-should-use-self.rs:3:13
    |
 LL |     fn f(a: A) -> A;
-   |             ^ `A` cannot be made into an object
+   |             ^ `A` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/dyn-incompatible-trait-should-use-self.rs:2:10
    |
 LL | trait A: Sized {
    |       -  ^^^^^ ...because it requires `Self: Sized`
    |       |
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
 
 error: associated item referring to unboxed trait object for its own trait
   --> $DIR/dyn-incompatible-trait-should-use-self.rs:8:13
@@ -38,17 +39,18 @@ help: you might have meant to use `Self` to refer to the implementing type
 LL |     fn f(a: Self) -> Self;
    |             ~~~~     ~~~~
 
-error[E0038]: the trait `B` cannot be made into an object
+error[E0038]: the trait `B` is not dyn compatible
   --> $DIR/dyn-incompatible-trait-should-use-self.rs:8:13
    |
 LL |     fn f(a: B) -> B;
-   |             ^ `B` cannot be made into an object
+   |             ^ `B` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/dyn-incompatible-trait-should-use-self.rs:8:8
    |
 LL | trait B {
-   |       - this trait cannot be made into an object...
+   |       - this trait is not dyn compatible...
 LL |     fn f(a: B) -> B;
    |        ^ ...because associated function `f` has no `self` parameter
 help: consider turning `f` into a method by giving it a `&self` argument
diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.fixed b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.fixed
index fd9b78934c7..2b26d8cc82e 100644
--- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.fixed
+++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.fixed
@@ -6,7 +6,7 @@ trait Trait {
     fn bar(self: &Self) {} //~ ERROR invalid `self` parameter type
 }
 
-fn bar(x: &dyn Trait) {} //~ ERROR the trait `Trait` cannot be made into an object
+fn bar(x: &dyn Trait) {} //~ ERROR the trait `Trait` is not dyn compatible
 
 trait Other {}
 
diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.rs b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.rs
index e4aa0d89239..b0b02dedb2b 100644
--- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.rs
+++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.rs
@@ -6,7 +6,7 @@ trait Trait {
     fn bar(self: ()) {} //~ ERROR invalid `self` parameter type
 }
 
-fn bar(x: &dyn Trait) {} //~ ERROR the trait `Trait` cannot be made into an object
+fn bar(x: &dyn Trait) {} //~ ERROR the trait `Trait` is not dyn compatible
 
 trait Other {}
 
diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr
index beafd7c2ab0..696840d3ba4 100644
--- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr
+++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr
@@ -1,14 +1,15 @@
-error[E0038]: the trait `Trait` cannot be made into an object
+error[E0038]: the trait `Trait` is not dyn compatible
   --> $DIR/dyn-incompatible-trait-should-use-where-sized.rs:9:12
    |
 LL | fn bar(x: &dyn Trait) {}
-   |            ^^^^^^^^^ `Trait` cannot be made into an object
+   |            ^^^^^^^^^ `Trait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/dyn-incompatible-trait-should-use-where-sized.rs:5:8
    |
 LL | trait Trait {
-   |       ----- this trait cannot be made into an object...
+   |       ----- this trait is not dyn compatible...
 LL |     fn foo() where Self: Other, { }
    |        ^^^ ...because associated function `foo` has no `self` parameter
 LL |     fn bar(self: ()) {}
diff --git a/tests/ui/suggestions/issue-116434-2015.rs b/tests/ui/suggestions/issue-116434-2015.rs
index 2e94473eb1a..1518765152f 100644
--- a/tests/ui/suggestions/issue-116434-2015.rs
+++ b/tests/ui/suggestions/issue-116434-2015.rs
@@ -7,7 +7,7 @@ trait Foo {
     //~| WARNING trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
     //~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
     //~| HELP if this is a dyn-compatible trait, use `dyn`
-    //~| ERROR the trait `Clone` cannot be made into an object [E0038]
+    //~| ERROR the trait `Clone` is not dyn compatible [E0038]
     //~| HELP there is an associated type with the same name
 }
 
@@ -22,7 +22,7 @@ trait DbInterface {
     //~| WARNING trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
     //~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
     //~| HELP if this is a dyn-compatible trait, use `dyn`
-    //~| ERROR the trait `DbHandle` cannot be made into an object [E0038]
+    //~| ERROR the trait `DbHandle` is not dyn compatible [E0038]
     //~| HELP there is an associated type with the same name
 }
 
diff --git a/tests/ui/suggestions/issue-116434-2015.stderr b/tests/ui/suggestions/issue-116434-2015.stderr
index 24fc87f765f..508c3ec5e4f 100644
--- a/tests/ui/suggestions/issue-116434-2015.stderr
+++ b/tests/ui/suggestions/issue-116434-2015.stderr
@@ -39,14 +39,15 @@ help: if this is a dyn-compatible trait, use `dyn`
 LL |     fn foo() -> dyn Clone;
    |                 +++
 
-error[E0038]: the trait `Clone` cannot be made into an object
+error[E0038]: the trait `Clone` is not dyn compatible
   --> $DIR/issue-116434-2015.rs:3:17
    |
 LL |     fn foo() -> Clone;
-   |                 ^^^^^ `Clone` cannot be made into an object
+   |                 ^^^^^ `Clone` is not dyn compatible
    |
-   = note: the trait cannot be made into an object because it requires `Self: Sized`
-   = note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+   = note: the trait is not dyn compatible because it requires `Self: Sized`
+   = note: for a trait to be dyn compatible it needs to allow building a vtable
+           for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
 help: there is an associated type with the same name
    |
 LL |     fn foo() -> Self::Clone;
@@ -66,19 +67,20 @@ help: if this is a dyn-compatible trait, use `dyn`
 LL |     fn handle() -> dyn DbHandle;
    |                    +++
 
-error[E0038]: the trait `DbHandle` cannot be made into an object
+error[E0038]: the trait `DbHandle` is not dyn compatible
   --> $DIR/issue-116434-2015.rs:18:20
    |
 LL |     fn handle() -> DbHandle;
-   |                    ^^^^^^^^ `DbHandle` cannot be made into an object
+   |                    ^^^^^^^^ `DbHandle` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-116434-2015.rs:14:17
    |
 LL | trait DbHandle: Sized {}
    |       --------  ^^^^^ ...because it requires `Self: Sized`
    |       |
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
 help: there is an associated type with the same name
    |
 LL |     fn handle() -> Self::DbHandle;
diff --git a/tests/ui/suggestions/issue-98500.rs b/tests/ui/suggestions/issue-98500.rs
index 289b16abf4b..869b665c8cb 100644
--- a/tests/ui/suggestions/issue-98500.rs
+++ b/tests/ui/suggestions/issue-98500.rs
@@ -9,6 +9,6 @@ pub trait B where
 }
 
 struct S(Box<dyn B>);
-//~^ ERROR the trait `B` cannot be made into an object
+//~^ ERROR the trait `B` is not dyn compatible
 
 fn main() {}
diff --git a/tests/ui/suggestions/issue-98500.stderr b/tests/ui/suggestions/issue-98500.stderr
index d7136ec1a64..97b712acfcb 100644
--- a/tests/ui/suggestions/issue-98500.stderr
+++ b/tests/ui/suggestions/issue-98500.stderr
@@ -1,10 +1,11 @@
-error[E0038]: the trait `B` cannot be made into an object
+error[E0038]: the trait `B` is not dyn compatible
   --> $DIR/issue-98500.rs:11:14
    |
 LL | struct S(Box<dyn B>);
-   |              ^^^^^ `B` cannot be made into an object
+   |              ^^^^^ `B` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/auxiliary/dyn-incompatible.rs:4:8
    |
 LL |     fn f();
@@ -15,7 +16,7 @@ LL |     fn f2(self: &Arc<Self>);
   ::: $DIR/issue-98500.rs:5:11
    |
 LL | pub trait B where
-   |           - this trait cannot be made into an object...
+   |           - this trait is not dyn compatible...
    = help: consider moving `f` to another trait
    = help: consider moving `f2` to another trait
 
diff --git a/tests/ui/test-attrs/test-runner-hides-start.rs b/tests/ui/test-attrs/test-runner-hides-start.rs
deleted file mode 100644
index 444ac237cfa..00000000000
--- a/tests/ui/test-attrs/test-runner-hides-start.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-//@ run-pass
-//@ compile-flags: --test
-
-#![feature(start)]
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize { panic!(); }
diff --git a/tests/ui/traits/alias/generic-default-in-dyn.rs b/tests/ui/traits/alias/generic-default-in-dyn.rs
index d44e1c2a975..b263e578c31 100644
--- a/tests/ui/traits/alias/generic-default-in-dyn.rs
+++ b/tests/ui/traits/alias/generic-default-in-dyn.rs
@@ -2,9 +2,9 @@ trait SendEqAlias<T> = PartialEq;
 //~^ ERROR trait aliases are experimental
 
 struct Foo<T>(dyn SendEqAlias<T>);
-//~^ ERROR the type parameter `Rhs` must be explicitly specified [E0393]
+//~^ ERROR the trait alias `SendEqAlias` is not dyn compatible
 
 struct Bar<T>(dyn SendEqAlias<T>, T);
-//~^ ERROR the type parameter `Rhs` must be explicitly specified [E0393]
+//~^ ERROR the trait alias `SendEqAlias` is not dyn compatible
 
 fn main() {}
diff --git a/tests/ui/traits/alias/generic-default-in-dyn.stderr b/tests/ui/traits/alias/generic-default-in-dyn.stderr
index 50031e184c1..1ab9e6d5c5c 100644
--- a/tests/ui/traits/alias/generic-default-in-dyn.stderr
+++ b/tests/ui/traits/alias/generic-default-in-dyn.stderr
@@ -8,29 +8,37 @@ LL | trait SendEqAlias<T> = PartialEq;
    = help: add `#![feature(trait_alias)]` 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[E0393]: the type parameter `Rhs` must be explicitly specified
+error[E0038]: the trait alias `SendEqAlias` is not dyn compatible
   --> $DIR/generic-default-in-dyn.rs:4:19
    |
 LL | struct Foo<T>(dyn SendEqAlias<T>);
-   |                   ^^^^^^^^^^^^^^ missing reference to `Rhs`
-  --> $SRC_DIR/core/src/cmp.rs:LL:COL
+   |                   ^^^^^^^^^^^^^^ `SendEqAlias` is not dyn compatible
    |
-   = note: type parameter `Rhs` must be specified for this
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/generic-default-in-dyn.rs:1:24
    |
-   = note: because of the default `Self` reference, type parameters must be specified on object types
+LL | trait SendEqAlias<T> = PartialEq;
+   |       -----------      ^^^^^^^^^ ...because it uses `Self` as a type parameter
+   |       |
+   |       this trait is not dyn compatible...
 
-error[E0393]: the type parameter `Rhs` must be explicitly specified
+error[E0038]: the trait alias `SendEqAlias` is not dyn compatible
   --> $DIR/generic-default-in-dyn.rs:7:19
    |
 LL | struct Bar<T>(dyn SendEqAlias<T>, T);
-   |                   ^^^^^^^^^^^^^^ missing reference to `Rhs`
-  --> $SRC_DIR/core/src/cmp.rs:LL:COL
+   |                   ^^^^^^^^^^^^^^ `SendEqAlias` is not dyn compatible
    |
-   = note: type parameter `Rhs` must be specified for this
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/generic-default-in-dyn.rs:1:24
    |
-   = note: because of the default `Self` reference, type parameters must be specified on object types
+LL | trait SendEqAlias<T> = PartialEq;
+   |       -----------      ^^^^^^^^^ ...because it uses `Self` as a type parameter
+   |       |
+   |       this trait is not dyn compatible...
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0393, E0658.
-For more information about an error, try `rustc --explain E0393`.
+Some errors have detailed explanations: E0038, E0658.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/tests/ui/traits/alias/no-duplicates.stderr b/tests/ui/traits/alias/no-duplicates.stderr
index bf244b97e9b..6a901a80554 100644
--- a/tests/ui/traits/alias/no-duplicates.stderr
+++ b/tests/ui/traits/alias/no-duplicates.stderr
@@ -4,32 +4,32 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec
 LL | trait _0 = Obj;
    |            ---
    |            |
-   |            additional non-auto trait
    |            first non-auto trait
+   |            additional non-auto trait
 ...
 LL | type _T00 = dyn _0 + _0;
-   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 --   ^^ second non-auto trait comes from this alias
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 first non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/no-duplicates.rs:19:22
+  --> $DIR/no-duplicates.rs:19:17
    |
 LL | trait _0 = Obj;
    |            ---
    |            |
-   |            additional non-auto trait
    |            first non-auto trait
+   |            additional non-auto trait
 LL | trait _1 = _0;
-   |            -- referenced here (first use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | type _T01 = dyn _1 + _0;
-   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 ^^   -- first non-auto trait comes from this alias
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 second non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
@@ -40,18 +40,18 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec
 LL | trait _0 = Obj;
    |            ---
    |            |
-   |            additional non-auto trait
    |            first non-auto trait
+   |            additional non-auto trait
 LL | trait _1 = _0;
    |            --
    |            |
-   |            referenced here (additional use)
-   |            referenced here (first use)
+   |            first non-auto trait comes from this alias
+   |            second non-auto trait comes from this alias
 ...
 LL | type _T02 = dyn _1 + _1;
-   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 --   ^^ second non-auto trait comes from this alias
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 first non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
@@ -62,10 +62,10 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec
 LL | trait _0 = Obj;
    |            --- additional non-auto trait
 LL | trait _1 = _0;
-   |            -- referenced here (additional use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | type _T03 = dyn Obj + _1;
-   |                 ---   ^^ trait alias used in trait object type (additional use)
+   |                 ---   ^^ second non-auto trait comes from this alias
    |                 |
    |                 first non-auto trait
    |
@@ -73,17 +73,17 @@ LL | type _T03 = dyn Obj + _1;
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/no-duplicates.rs:28:22
+  --> $DIR/no-duplicates.rs:28:17
    |
 LL | trait _0 = Obj;
-   |            --- first non-auto trait
+   |            --- additional non-auto trait
 LL | trait _1 = _0;
-   |            -- referenced here (first use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | type _T04 = dyn _1 + Obj;
-   |                 --   ^^^ additional non-auto trait
+   |                 ^^   --- first non-auto trait
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 second non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
@@ -92,23 +92,17 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec
   --> $DIR/no-duplicates.rs:37:17
    |
 LL | trait _0 = Obj;
-   |            ---
-   |            |
-   |            additional non-auto trait
-   |            first non-auto trait
-LL | trait _1 = _0;
-   |            -- referenced here (additional use)
+   |            --- additional non-auto trait
 ...
 LL | trait _2 = _0 + _1;
-   |            --   -- referenced here (additional use)
-   |            |
-   |            referenced here (first use)
+   |            -- second non-auto trait comes from this alias
+LL | trait _3 = Obj;
+   |            --- first non-auto trait
 ...
 LL | type _T10 = dyn _2 + _3;
-   |                 ^^
+   |                 ^^   -- first non-auto trait comes from this alias
    |                 |
-   |                 trait alias used in trait object type (additional use)
-   |                 trait alias used in trait object type (first use)
+   |                 second non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
@@ -120,14 +114,14 @@ LL | trait _0 = Obj;
    |            --- additional non-auto trait
 ...
 LL | trait _2 = _0 + _1;
-   |            -- referenced here (additional use)
+   |            -- second non-auto trait comes from this alias
 LL | trait _3 = Obj;
    |            --- first non-auto trait
 ...
 LL | type _T11 = dyn _3 + _2;
-   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 --   ^^ second non-auto trait comes from this alias
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 first non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
@@ -139,10 +133,10 @@ LL | trait _0 = Obj;
    |            --- additional non-auto trait
 ...
 LL | trait _2 = _0 + _1;
-   |            -- referenced here (additional use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | type _T12 = dyn Obj + _2;
-   |                 ---   ^^ trait alias used in trait object type (additional use)
+   |                 ---   ^^ second non-auto trait comes from this alias
    |                 |
    |                 first non-auto trait
    |
@@ -153,42 +147,34 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec
   --> $DIR/no-duplicates.rs:46:17
    |
 LL | trait _0 = Obj;
-   |            ---
-   |            |
-   |            additional non-auto trait
-   |            first non-auto trait
-LL | trait _1 = _0;
-   |            -- referenced here (additional use)
+   |            --- additional non-auto trait
 ...
 LL | trait _2 = _0 + _1;
-   |            --   -- referenced here (additional use)
-   |            |
-   |            referenced here (first use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | type _T13 = dyn _2 + Obj;
-   |                 ^^
+   |                 ^^   --- first non-auto trait
    |                 |
-   |                 trait alias used in trait object type (additional use)
-   |                 trait alias used in trait object type (first use)
+   |                 second non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/no-duplicates.rs:49:22
+  --> $DIR/no-duplicates.rs:49:17
    |
 LL | trait _0 = Obj;
-   |            --- first non-auto trait
+   |            --- additional non-auto trait
 LL | trait _1 = _0;
-   |            -- referenced here (first use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | trait _3 = Obj;
-   |            --- additional non-auto trait
+   |            --- first non-auto trait
 ...
 LL | type _T14 = dyn _1 + _3;
-   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 ^^   -- first non-auto trait comes from this alias
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 second non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
@@ -199,15 +185,15 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec
 LL | trait _0 = Obj;
    |            --- additional non-auto trait
 LL | trait _1 = _0;
-   |            -- referenced here (additional use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | trait _3 = Obj;
    |            --- first non-auto trait
 ...
 LL | type _T15 = dyn _3 + _1;
-   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 --   ^^ second non-auto trait comes from this alias
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 first non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
@@ -218,17 +204,17 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec
 LL | trait _0 = Obj;
    |            --- first non-auto trait
 LL | trait _1 = _0;
-   |            -- referenced here (first use)
+   |            -- first non-auto trait comes from this alias
 ...
 LL | trait _3 = Obj;
    |            --- additional non-auto trait
 LL | trait _4 = _3;
-   |            -- referenced here (additional use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | type _T16 = dyn _1 + _4;
-   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 --   ^^ second non-auto trait comes from this alias
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 first non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
@@ -239,17 +225,17 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec
 LL | trait _0 = Obj;
    |            --- additional non-auto trait
 LL | trait _1 = _0;
-   |            -- referenced here (additional use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | trait _3 = Obj;
    |            --- first non-auto trait
 LL | trait _4 = _3;
-   |            -- referenced here (first use)
+   |            -- first non-auto trait comes from this alias
 ...
 LL | type _T17 = dyn _4 + _1;
-   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 --   ^^ second non-auto trait comes from this alias
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 first non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
@@ -260,13 +246,13 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec
 LL | trait _5 = Obj + Send;
    |            ---
    |            |
-   |            additional non-auto trait
    |            first non-auto trait
+   |            additional non-auto trait
 LL |
 LL | type _T20 = dyn _5 + _5;
-   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 --   ^^ second non-auto trait comes from this alias
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 first non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
@@ -278,7 +264,7 @@ LL | trait _5 = Obj + Send;
    |            --- additional non-auto trait
 ...
 LL | type _T21 = dyn Obj + _5;
-   |                 ---   ^^ trait alias used in trait object type (additional use)
+   |                 ---   ^^ second non-auto trait comes from this alias
    |                 |
    |                 first non-auto trait
    |
@@ -286,29 +272,29 @@ LL | type _T21 = dyn Obj + _5;
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/no-duplicates.rs:71:22
+  --> $DIR/no-duplicates.rs:71:17
    |
 LL | trait _5 = Obj + Send;
-   |            --- first non-auto trait
+   |            --- additional non-auto trait
 ...
 LL | type _T22 = dyn _5 + Obj;
-   |                 --   ^^^ additional non-auto trait
+   |                 ^^   --- first non-auto trait
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 second non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/no-duplicates.rs:74:36
+  --> $DIR/no-duplicates.rs:74:17
    |
 LL | trait _5 = Obj + Send;
-   |            --- first non-auto trait
+   |            --- additional non-auto trait
 ...
 LL | type _T23 = dyn _5 + Send + Sync + Obj;
-   |                 --                 ^^^ additional non-auto trait
+   |                 ^^                 --- first non-auto trait
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 second non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
@@ -319,19 +305,19 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec
 LL | trait _5 = Obj + Send;
    |            ---
    |            |
-   |            additional non-auto trait
    |            first non-auto trait
+   |            additional non-auto trait
 ...
 LL | trait _6 = _5 + _5; // ==> Obj + Send + Obj + Send
-   |            --   -- referenced here (additional use)
+   |            --   -- second non-auto trait comes from this alias
    |            |
-   |            referenced here (first use)
+   |            first non-auto trait comes from this alias
 LL |
 LL | type _T30 = dyn _6;
    |                 ^^
    |                 |
-   |                 trait alias used in trait object type (additional use)
-   |                 trait alias used in trait object type (first use)
+   |                 first non-auto trait comes from this alias
+   |                 second non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
@@ -342,19 +328,19 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec
 LL | trait _5 = Obj + Send;
    |            ---
    |            |
-   |            additional non-auto trait
    |            first non-auto trait
+   |            additional non-auto trait
 ...
 LL | trait _6 = _5 + _5; // ==> Obj + Send + Obj + Send
-   |            --   -- referenced here (additional use)
+   |            --   -- second non-auto trait comes from this alias
    |            |
-   |            referenced here (first use)
+   |            first non-auto trait comes from this alias
 ...
 LL | type _T31 = dyn _6 + Send;
    |                 ^^
    |                 |
-   |                 trait alias used in trait object type (additional use)
-   |                 trait alias used in trait object type (first use)
+   |                 first non-auto trait comes from this alias
+   |                 second non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
@@ -365,38 +351,38 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec
 LL | trait _5 = Obj + Send;
    |            ---
    |            |
-   |            additional non-auto trait
    |            first non-auto trait
+   |            additional non-auto trait
 ...
 LL | trait _6 = _5 + _5; // ==> Obj + Send + Obj + Send
-   |            --   -- referenced here (additional use)
+   |            --   -- second non-auto trait comes from this alias
    |            |
-   |            referenced here (first use)
+   |            first non-auto trait comes from this alias
 ...
 LL | type _T32 = dyn Send + _6;
    |                        ^^
    |                        |
-   |                        trait alias used in trait object type (additional use)
-   |                        trait alias used in trait object type (first use)
+   |                        first non-auto trait comes from this alias
+   |                        second non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/no-duplicates.rs:95:22
+  --> $DIR/no-duplicates.rs:95:17
    |
 LL | trait _5 = Obj + Send;
-   |            --- first non-auto trait
+   |            --- additional non-auto trait
 ...
 LL | trait _7 = _5 + Sync;
-   |            -- referenced here (first use)
+   |            -- second non-auto trait comes from this alias
 LL | trait _8 = Unpin + _7;
-   |                    -- referenced here (first use)
+   |                    -- second non-auto trait comes from this alias
 LL |
 LL | type _T40 = dyn _8 + Obj;
-   |                 --   ^^^ additional non-auto trait
+   |                 ^^   --- first non-auto trait
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 second non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
@@ -408,12 +394,12 @@ LL | trait _5 = Obj + Send;
    |            --- additional non-auto trait
 ...
 LL | trait _7 = _5 + Sync;
-   |            -- referenced here (additional use)
+   |            -- second non-auto trait comes from this alias
 LL | trait _8 = Unpin + _7;
-   |                    -- referenced here (additional use)
+   |                    -- second non-auto trait comes from this alias
 ...
 LL | type _T41 = dyn Obj + _8;
-   |                 ---   ^^ trait alias used in trait object type (additional use)
+   |                 ---   ^^ second non-auto trait comes from this alias
    |                 |
    |                 first non-auto trait
    |
@@ -421,25 +407,25 @@ LL | type _T41 = dyn Obj + _8;
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/no-duplicates.rs:101:22
+  --> $DIR/no-duplicates.rs:101:17
    |
 LL | trait _3 = Obj;
-   |            --- additional non-auto trait
+   |            --- first non-auto trait
 LL | trait _4 = _3;
-   |            -- referenced here (additional use)
+   |            -- first non-auto trait comes from this alias
 ...
 LL | trait _5 = Obj + Send;
-   |            --- first non-auto trait
+   |            --- additional non-auto trait
 ...
 LL | trait _7 = _5 + Sync;
-   |            -- referenced here (first use)
+   |            -- second non-auto trait comes from this alias
 LL | trait _8 = Unpin + _7;
-   |                    -- referenced here (first use)
+   |                    -- second non-auto trait comes from this alias
 ...
 LL | type _T42 = dyn _8 + _4;
-   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 ^^   -- first non-auto trait comes from this alias
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 second non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
@@ -450,20 +436,20 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec
 LL | trait _3 = Obj;
    |            --- first non-auto trait
 LL | trait _4 = _3;
-   |            -- referenced here (first use)
+   |            -- first non-auto trait comes from this alias
 ...
 LL | trait _5 = Obj + Send;
    |            --- additional non-auto trait
 ...
 LL | trait _7 = _5 + Sync;
-   |            -- referenced here (additional use)
+   |            -- second non-auto trait comes from this alias
 LL | trait _8 = Unpin + _7;
-   |                    -- referenced here (additional use)
+   |                    -- second non-auto trait comes from this alias
 ...
 LL | type _T43 = dyn _4 + _8;
-   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 --   ^^ second non-auto trait comes from this alias
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 first non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
@@ -474,20 +460,20 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec
 LL | trait _3 = Obj;
    |            --- first non-auto trait
 LL | trait _4 = _3;
-   |            -- referenced here (first use)
+   |            -- first non-auto trait comes from this alias
 ...
 LL | trait _5 = Obj + Send;
    |            --- additional non-auto trait
 ...
 LL | trait _7 = _5 + Sync;
-   |            -- referenced here (additional use)
+   |            -- second non-auto trait comes from this alias
 LL | trait _8 = Unpin + _7;
-   |                    -- referenced here (additional use)
+   |                    -- second non-auto trait comes from this alias
 ...
 LL | type _T44 = dyn _4 + Send + Sync + _8;
-   |                 --                 ^^ trait alias used in trait object type (additional use)
+   |                 --                 ^^ second non-auto trait comes from this alias
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 first non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
@@ -500,9 +486,9 @@ LL | trait _9 = for<'a> ObjL<'a>;
 LL | trait _10 = for<'b> ObjL<'b>;
    |             ---------------- additional non-auto trait
 LL | type _T50 = dyn _9 + _10;
-   |                 --   ^^^ trait alias used in trait object type (additional use)
+   |                 --   ^^^ second non-auto trait comes from this alias
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 first non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: for<'a> ObjL<'a> + for<'b> ObjL<'b> {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
@@ -515,9 +501,9 @@ LL | trait _11 = ObjT<for<'a> fn(&'a u8)>;
 LL | trait _12 = ObjT<for<'b> fn(&'b u8)>;
    |             ------------------------ additional non-auto trait
 LL | type _T60 = dyn _11 + _12;
-   |                 ---   ^^^ trait alias used in trait object type (additional use)
+   |                 ---   ^^^ second non-auto trait comes from this alias
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 first non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjT<for<'a> fn(&'a u8)> + ObjT<for<'b> fn(&'b u8)> {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
diff --git a/tests/ui/traits/alias/no-extra-traits.stderr b/tests/ui/traits/alias/no-extra-traits.stderr
index 4b1ddf6843c..fcdb4937ff5 100644
--- a/tests/ui/traits/alias/no-extra-traits.stderr
+++ b/tests/ui/traits/alias/no-extra-traits.stderr
@@ -1,15 +1,15 @@
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/no-extra-traits.rs:16:22
+  --> $DIR/no-extra-traits.rs:16:17
    |
 LL | trait _0 = ObjA;
-   |            ---- first non-auto trait
+   |            ---- additional non-auto trait
 ...
 LL | type _T00 = dyn _0 + ObjB;
-   |                 --   ^^^^ additional non-auto trait
+   |                 ^^   ---- first non-auto trait
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 second non-auto trait comes from this alias
    |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}`
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
@@ -19,7 +19,7 @@ LL | trait _0 = ObjA;
    |            ---- additional non-auto trait
 ...
 LL | type _T01 = dyn ObjB + _0;
-   |                 ----   ^^ trait alias used in trait object type (additional use)
+   |                 ----   ^^ second non-auto trait comes from this alias
    |                 |
    |                 first non-auto trait
    |
@@ -32,10 +32,10 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec
 LL | trait _0 = ObjA;
    |            ---- additional non-auto trait
 LL | trait _1 = _0;
-   |            -- referenced here (additional use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | type _T02 = dyn ObjB + _1;
-   |                 ----   ^^ trait alias used in trait object type (additional use)
+   |                 ----   ^^ second non-auto trait comes from this alias
    |                 |
    |                 first non-auto trait
    |
@@ -43,19 +43,19 @@ LL | type _T02 = dyn ObjB + _1;
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/no-extra-traits.rs:25:22
+  --> $DIR/no-extra-traits.rs:25:17
    |
 LL | trait _0 = ObjA;
-   |            ---- first non-auto trait
+   |            ---- additional non-auto trait
 LL | trait _1 = _0;
-   |            -- referenced here (first use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | type _T03 = dyn _1 + ObjB;
-   |                 --   ^^^^ additional non-auto trait
+   |                 ^^   ---- first non-auto trait
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 second non-auto trait comes from this alias
    |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}`
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
@@ -64,34 +64,34 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec
 LL | trait _2 = ObjB;
    |            ----
    |            |
-   |            additional non-auto trait
    |            first non-auto trait
+   |            additional non-auto trait
 LL | trait _3 = _2;
-   |            -- referenced here (additional use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | type _T10 = dyn _2 + _3;
-   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 --   ^^ second non-auto trait comes from this alias
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 first non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/no-extra-traits.rs:37:22
+  --> $DIR/no-extra-traits.rs:37:17
    |
 LL | trait _2 = ObjB;
    |            ----
    |            |
-   |            additional non-auto trait
    |            first non-auto trait
+   |            additional non-auto trait
 LL | trait _3 = _2;
-   |            -- referenced here (first use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | type _T11 = dyn _3 + _2;
-   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 ^^   -- first non-auto trait comes from this alias
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 second non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
@@ -102,38 +102,38 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec
 LL | trait _2 = ObjB;
    |            ----
    |            |
-   |            additional non-auto trait
    |            first non-auto trait
+   |            additional non-auto trait
 LL | trait _3 = _2;
-   |            -- referenced here (additional use)
+   |            -- second non-auto trait comes from this alias
 LL | trait _4 = _3;
-   |            -- referenced here (additional use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | type _T12 = dyn _2 + _4;
-   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 --   ^^ second non-auto trait comes from this alias
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 first non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/no-extra-traits.rs:43:22
+  --> $DIR/no-extra-traits.rs:43:17
    |
 LL | trait _2 = ObjB;
    |            ----
    |            |
-   |            additional non-auto trait
    |            first non-auto trait
+   |            additional non-auto trait
 LL | trait _3 = _2;
-   |            -- referenced here (first use)
+   |            -- second non-auto trait comes from this alias
 LL | trait _4 = _3;
-   |            -- referenced here (first use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | type _T13 = dyn _4 + _2;
-   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 ^^   -- first non-auto trait comes from this alias
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 second non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
@@ -144,50 +144,50 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec
 LL | trait _0 = ObjA;
    |            ---- additional non-auto trait
 LL | trait _1 = _0;
-   |            -- referenced here (additional use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | trait _5 = Sync + ObjB + Send;
    |                   ---- first non-auto trait
 LL |
 LL | type _T20 = dyn _5 + _1;
-   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 --   ^^ second non-auto trait comes from this alias
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 first non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/no-extra-traits.rs:53:22
+  --> $DIR/no-extra-traits.rs:53:17
    |
 LL | trait _0 = ObjA;
-   |            ---- first non-auto trait
+   |            ---- additional non-auto trait
 LL | trait _1 = _0;
-   |            -- referenced here (first use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | trait _5 = Sync + ObjB + Send;
-   |                   ---- additional non-auto trait
+   |                   ---- first non-auto trait
 ...
 LL | type _T21 = dyn _1 + _5;
-   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 ^^   -- first non-auto trait comes from this alias
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 second non-auto trait comes from this alias
    |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}`
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/no-extra-traits.rs:56:22
+  --> $DIR/no-extra-traits.rs:56:17
    |
 LL | trait _5 = Sync + ObjB + Send;
-   |                   ---- first non-auto trait
+   |                   ---- additional non-auto trait
 ...
 LL | type _T22 = dyn _5 + ObjA;
-   |                 --   ^^^^ additional non-auto trait
+   |                 ^^   ---- first non-auto trait
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 second non-auto trait comes from this alias
    |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}`
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
@@ -197,7 +197,7 @@ LL | trait _5 = Sync + ObjB + Send;
    |                   ---- additional non-auto trait
 ...
 LL | type _T23 = dyn ObjA + _5;
-   |                 ----   ^^ trait alias used in trait object type (additional use)
+   |                 ----   ^^ second non-auto trait comes from this alias
    |                 |
    |                 first non-auto trait
    |
@@ -210,50 +210,50 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec
 LL | trait _0 = ObjA;
    |            ---- additional non-auto trait
 LL | trait _1 = _0;
-   |            -- referenced here (additional use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | trait _5 = Sync + ObjB + Send;
    |                   ---- first non-auto trait
 ...
 LL | type _T24 = dyn Send + _5 + _1 + Sync;
-   |                        --   ^^ trait alias used in trait object type (additional use)
+   |                        --   ^^ second non-auto trait comes from this alias
    |                        |
-   |                        trait alias used in trait object type (first use)
+   |                        first non-auto trait comes from this alias
    |
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/no-extra-traits.rs:65:29
+  --> $DIR/no-extra-traits.rs:65:17
    |
 LL | trait _0 = ObjA;
-   |            ---- first non-auto trait
+   |            ---- additional non-auto trait
 LL | trait _1 = _0;
-   |            -- referenced here (first use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | trait _5 = Sync + ObjB + Send;
-   |                   ---- additional non-auto trait
+   |                   ---- first non-auto trait
 ...
 LL | type _T25 = dyn _1 + Sync + _5 + Send;
-   |                 --          ^^ trait alias used in trait object type (additional use)
+   |                 ^^          -- first non-auto trait comes from this alias
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 second non-auto trait comes from this alias
    |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}`
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/no-extra-traits.rs:68:36
+  --> $DIR/no-extra-traits.rs:68:31
    |
 LL | trait _5 = Sync + ObjB + Send;
-   |                   ---- first non-auto trait
+   |                   ---- additional non-auto trait
 ...
 LL | type _T26 = dyn Sync + Send + _5 + ObjA;
-   |                               --   ^^^^ additional non-auto trait
+   |                               ^^   ---- first non-auto trait
    |                               |
-   |                               trait alias used in trait object type (first use)
+   |                               second non-auto trait comes from this alias
    |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}`
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
@@ -263,7 +263,7 @@ LL | trait _5 = Sync + ObjB + Send;
    |                   ---- additional non-auto trait
 ...
 LL | type _T27 = dyn Send + Sync + ObjA + _5;
-   |                               ----   ^^ trait alias used in trait object type (additional use)
+   |                               ----   ^^ second non-auto trait comes from this alias
    |                               |
    |                               first non-auto trait
    |
@@ -274,199 +274,199 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec
   --> $DIR/no-extra-traits.rs:80:17
    |
 LL | trait _0 = ObjA;
-   |            ---- first non-auto trait
+   |            ---- additional non-auto trait
 LL | trait _1 = _0;
-   |            -- referenced here (first use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | trait _5 = Sync + ObjB + Send;
-   |                   ---- additional non-auto trait
+   |                   ---- first non-auto trait
 ...
 LL | trait _6 = _1 + _5;
-   |            --   -- referenced here (additional use)
+   |            --   -- first non-auto trait comes from this alias
    |            |
-   |            referenced here (first use)
+   |            second non-auto trait comes from this alias
 ...
 LL | type _T30 = dyn _6;
    |                 ^^
    |                 |
-   |                 trait alias used in trait object type (additional use)
-   |                 trait alias used in trait object type (first use)
+   |                 first non-auto trait comes from this alias
+   |                 second non-auto trait comes from this alias
    |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}`
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
   --> $DIR/no-extra-traits.rs:83:17
    |
 LL | trait _0 = ObjA;
-   |            ---- first non-auto trait
+   |            ---- additional non-auto trait
 LL | trait _1 = _0;
-   |            -- referenced here (first use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | trait _5 = Sync + ObjB + Send;
-   |                   ---- additional non-auto trait
+   |                   ---- first non-auto trait
 ...
 LL | trait _6 = _1 + _5;
-   |            --   -- referenced here (additional use)
+   |            --   -- first non-auto trait comes from this alias
    |            |
-   |            referenced here (first use)
+   |            second non-auto trait comes from this alias
 ...
 LL | type _T31 = dyn _6 + Send;
    |                 ^^
    |                 |
-   |                 trait alias used in trait object type (additional use)
-   |                 trait alias used in trait object type (first use)
+   |                 first non-auto trait comes from this alias
+   |                 second non-auto trait comes from this alias
    |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}`
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
   --> $DIR/no-extra-traits.rs:86:24
    |
 LL | trait _0 = ObjA;
-   |            ---- first non-auto trait
+   |            ---- additional non-auto trait
 LL | trait _1 = _0;
-   |            -- referenced here (first use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | trait _5 = Sync + ObjB + Send;
-   |                   ---- additional non-auto trait
+   |                   ---- first non-auto trait
 ...
 LL | trait _6 = _1 + _5;
-   |            --   -- referenced here (additional use)
+   |            --   -- first non-auto trait comes from this alias
    |            |
-   |            referenced here (first use)
+   |            second non-auto trait comes from this alias
 ...
 LL | type _T32 = dyn Send + _6;
    |                        ^^
    |                        |
-   |                        trait alias used in trait object type (additional use)
-   |                        trait alias used in trait object type (first use)
+   |                        first non-auto trait comes from this alias
+   |                        second non-auto trait comes from this alias
    |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}`
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
   --> $DIR/no-extra-traits.rs:89:17
    |
 LL | trait _0 = ObjA;
-   |            ---- first non-auto trait
+   |            ---- additional non-auto trait
 LL | trait _1 = _0;
-   |            -- referenced here (first use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | trait _5 = Sync + ObjB + Send;
-   |                   ---- additional non-auto trait
+   |                   ---- first non-auto trait
 ...
 LL | trait _6 = _1 + _5;
-   |            --   -- referenced here (additional use)
+   |            --   -- first non-auto trait comes from this alias
    |            |
-   |            referenced here (first use)
+   |            second non-auto trait comes from this alias
 LL | trait _7 = _6;
    |            --
    |            |
-   |            referenced here (additional use)
-   |            referenced here (first use)
+   |            first non-auto trait comes from this alias
+   |            second non-auto trait comes from this alias
 LL | trait _8 = _7;
    |            --
    |            |
-   |            referenced here (additional use)
-   |            referenced here (first use)
+   |            first non-auto trait comes from this alias
+   |            second non-auto trait comes from this alias
 ...
 LL | type _T33 = dyn _8;
    |                 ^^
    |                 |
-   |                 trait alias used in trait object type (additional use)
-   |                 trait alias used in trait object type (first use)
+   |                 first non-auto trait comes from this alias
+   |                 second non-auto trait comes from this alias
    |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}`
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
   --> $DIR/no-extra-traits.rs:92:17
    |
 LL | trait _0 = ObjA;
-   |            ---- first non-auto trait
+   |            ---- additional non-auto trait
 LL | trait _1 = _0;
-   |            -- referenced here (first use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | trait _5 = Sync + ObjB + Send;
-   |                   ---- additional non-auto trait
+   |                   ---- first non-auto trait
 ...
 LL | trait _6 = _1 + _5;
-   |            --   -- referenced here (additional use)
+   |            --   -- first non-auto trait comes from this alias
    |            |
-   |            referenced here (first use)
+   |            second non-auto trait comes from this alias
 LL | trait _7 = _6;
    |            --
    |            |
-   |            referenced here (additional use)
-   |            referenced here (first use)
+   |            first non-auto trait comes from this alias
+   |            second non-auto trait comes from this alias
 LL | trait _8 = _7;
    |            --
    |            |
-   |            referenced here (additional use)
-   |            referenced here (first use)
+   |            first non-auto trait comes from this alias
+   |            second non-auto trait comes from this alias
 ...
 LL | type _T34 = dyn _8 + Send;
    |                 ^^
    |                 |
-   |                 trait alias used in trait object type (additional use)
-   |                 trait alias used in trait object type (first use)
+   |                 first non-auto trait comes from this alias
+   |                 second non-auto trait comes from this alias
    |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}`
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
   --> $DIR/no-extra-traits.rs:95:24
    |
 LL | trait _0 = ObjA;
-   |            ---- first non-auto trait
+   |            ---- additional non-auto trait
 LL | trait _1 = _0;
-   |            -- referenced here (first use)
+   |            -- second non-auto trait comes from this alias
 ...
 LL | trait _5 = Sync + ObjB + Send;
-   |                   ---- additional non-auto trait
+   |                   ---- first non-auto trait
 ...
 LL | trait _6 = _1 + _5;
-   |            --   -- referenced here (additional use)
+   |            --   -- first non-auto trait comes from this alias
    |            |
-   |            referenced here (first use)
+   |            second non-auto trait comes from this alias
 LL | trait _7 = _6;
    |            --
    |            |
-   |            referenced here (additional use)
-   |            referenced here (first use)
+   |            first non-auto trait comes from this alias
+   |            second non-auto trait comes from this alias
 LL | trait _8 = _7;
    |            --
    |            |
-   |            referenced here (additional use)
-   |            referenced here (first use)
+   |            first non-auto trait comes from this alias
+   |            second non-auto trait comes from this alias
 ...
 LL | type _T35 = dyn Send + _8;
    |                        ^^
    |                        |
-   |                        trait alias used in trait object type (additional use)
-   |                        trait alias used in trait object type (first use)
+   |                        first non-auto trait comes from this alias
+   |                        second non-auto trait comes from this alias
    |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}`
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/no-extra-traits.rs:103:23
+  --> $DIR/no-extra-traits.rs:103:17
    |
 LL | trait _5 = Sync + ObjB + Send;
-   |                   ---- first non-auto trait
+   |                   ---- additional non-auto trait
 ...
 LL | trait _9 = _5 + Sync;
-   |            -- referenced here (first use)
+   |            -- second non-auto trait comes from this alias
 LL | trait _10 = Unpin + _9;
-   |                     -- referenced here (first use)
+   |                     -- second non-auto trait comes from this alias
 LL |
 LL | type _T40 = dyn _10 + ObjA;
-   |                 ---   ^^^^ additional non-auto trait
+   |                 ^^^   ---- first non-auto trait
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 second non-auto trait comes from this alias
    |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}`
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
@@ -476,12 +476,12 @@ LL | trait _5 = Sync + ObjB + Send;
    |                   ---- additional non-auto trait
 ...
 LL | trait _9 = _5 + Sync;
-   |            -- referenced here (additional use)
+   |            -- second non-auto trait comes from this alias
 LL | trait _10 = Unpin + _9;
-   |                     -- referenced here (additional use)
+   |                     -- second non-auto trait comes from this alias
 ...
 LL | type _T41 = dyn ObjA + _10;
-   |                 ----   ^^^ trait alias used in trait object type (additional use)
+   |                 ----   ^^^ second non-auto trait comes from this alias
    |                 |
    |                 first non-auto trait
    |
@@ -489,46 +489,46 @@ LL | type _T41 = dyn ObjA + _10;
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/no-extra-traits.rs:109:23
+  --> $DIR/no-extra-traits.rs:109:17
    |
 LL | trait _0 = ObjA;
-   |            ---- additional non-auto trait
+   |            ---- first non-auto trait
 LL | trait _1 = _0;
-   |            -- referenced here (additional use)
+   |            -- first non-auto trait comes from this alias
 ...
 LL | trait _5 = Sync + ObjB + Send;
-   |                   ---- first non-auto trait
+   |                   ---- additional non-auto trait
 ...
 LL | trait _9 = _5 + Sync;
-   |            -- referenced here (first use)
+   |            -- second non-auto trait comes from this alias
 LL | trait _10 = Unpin + _9;
-   |                     -- referenced here (first use)
+   |                     -- second non-auto trait comes from this alias
 ...
 LL | type _T42 = dyn _10 + _1;
-   |                 ---   ^^ trait alias used in trait object type (additional use)
+   |                 ^^^   -- first non-auto trait comes from this alias
    |                 |
-   |                 trait alias used in trait object type (first use)
+   |                 second non-auto trait comes from this alias
    |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}`
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/no-extra-traits.rs:112:37
+  --> $DIR/no-extra-traits.rs:112:24
    |
 LL | trait _5 = Sync + ObjB + Send;
-   |                   ---- first non-auto trait
+   |                   ---- additional non-auto trait
 ...
 LL | trait _9 = _5 + Sync;
-   |            -- referenced here (first use)
+   |            -- second non-auto trait comes from this alias
 LL | trait _10 = Unpin + _9;
-   |                     -- referenced here (first use)
+   |                     -- second non-auto trait comes from this alias
 ...
 LL | type _T43 = dyn Send + _10 + Sync + ObjA;
-   |                        ---          ^^^^ additional non-auto trait
+   |                        ^^^          ---- first non-auto trait
    |                        |
-   |                        trait alias used in trait object type (first use)
+   |                        second non-auto trait comes from this alias
    |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}`
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
@@ -538,12 +538,12 @@ LL | trait _5 = Sync + ObjB + Send;
    |                   ---- additional non-auto trait
 ...
 LL | trait _9 = _5 + Sync;
-   |            -- referenced here (additional use)
+   |            -- second non-auto trait comes from this alias
 LL | trait _10 = Unpin + _9;
-   |                     -- referenced here (additional use)
+   |                     -- second non-auto trait comes from this alias
 ...
 LL | type _T44 = dyn ObjA + _10 + Send + Sync;
-   |                 ----   ^^^ trait alias used in trait object type (additional use)
+   |                 ----   ^^^ second non-auto trait comes from this alias
    |                 |
    |                 first non-auto trait
    |
@@ -551,27 +551,27 @@ LL | type _T44 = dyn ObjA + _10 + Send + Sync;
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/no-extra-traits.rs:118:37
+  --> $DIR/no-extra-traits.rs:118:31
    |
 LL | trait _0 = ObjA;
-   |            ---- additional non-auto trait
+   |            ---- first non-auto trait
 LL | trait _1 = _0;
-   |            -- referenced here (additional use)
+   |            -- first non-auto trait comes from this alias
 ...
 LL | trait _5 = Sync + ObjB + Send;
-   |                   ---- first non-auto trait
+   |                   ---- additional non-auto trait
 ...
 LL | trait _9 = _5 + Sync;
-   |            -- referenced here (first use)
+   |            -- second non-auto trait comes from this alias
 LL | trait _10 = Unpin + _9;
-   |                     -- referenced here (first use)
+   |                     -- second non-auto trait comes from this alias
 ...
 LL | type _T45 = dyn Sync + Send + _10 + _1;
-   |                               ---   ^^ trait alias used in trait object type (additional use)
+   |                               ^^^   -- first non-auto trait comes from this alias
    |                               |
-   |                               trait alias used in trait object type (first use)
+   |                               second non-auto trait comes from this alias
    |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}`
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error: aborting due to 28 previous errors
diff --git a/tests/ui/traits/alias/object-fail.rs b/tests/ui/traits/alias/object-fail.rs
index 5c753ff207c..9a1cbad53e7 100644
--- a/tests/ui/traits/alias/object-fail.rs
+++ b/tests/ui/traits/alias/object-fail.rs
@@ -5,7 +5,7 @@ trait IteratorAlias = Iterator;
 
 fn main() {
     let _: &dyn EqAlias = &123;
-    //~^ ERROR the trait `Eq` cannot be made into an object [E0038]
+    //~^ ERROR the trait alias `EqAlias` is not dyn compatible [E0038]
     let _: &dyn IteratorAlias = &vec![123].into_iter();
     //~^ ERROR must be specified
 }
diff --git a/tests/ui/traits/alias/object-fail.stderr b/tests/ui/traits/alias/object-fail.stderr
index 1b89b87db9f..52ce79a4597 100644
--- a/tests/ui/traits/alias/object-fail.stderr
+++ b/tests/ui/traits/alias/object-fail.stderr
@@ -1,13 +1,19 @@
-error[E0038]: the trait `Eq` cannot be made into an object
-  --> $DIR/object-fail.rs:7:13
+error[E0038]: the trait alias `EqAlias` is not dyn compatible
+  --> $DIR/object-fail.rs:7:17
    |
 LL |     let _: &dyn EqAlias = &123;
-   |             ^^^^^^^^^^^ `Eq` cannot be made into an object
+   |                 ^^^^^^^ `EqAlias` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $SRC_DIR/core/src/cmp.rs:LL:COL
    |
-   = note: the trait cannot be made into an object because it uses `Self` as a type parameter
+   = note: ...because it uses `Self` as a type parameter
+   |
+  ::: $DIR/object-fail.rs:3:7
+   |
+LL | trait EqAlias = Eq;
+   |       ------- this trait is not dyn compatible...
 
 error[E0191]: the value of the associated type `Item` in `Iterator` must be specified
   --> $DIR/object-fail.rs:9:17
diff --git a/tests/ui/traits/alias/self-in-const-generics.rs b/tests/ui/traits/alias/self-in-const-generics.rs
index b0de8ccd678..a7d0ac9cbb4 100644
--- a/tests/ui/traits/alias/self-in-const-generics.rs
+++ b/tests/ui/traits/alias/self-in-const-generics.rs
@@ -7,6 +7,6 @@ trait Bar<const N: usize> {}
 trait BB = Bar<{ 2 + 1 }>;
 
 fn foo(x: &dyn BB) {}
-//~^ ERROR the trait alias `BB` cannot be made into an object [E0038]
+//~^ ERROR the trait alias `BB` is not dyn compatible [E0038]
 
 fn main() {}
diff --git a/tests/ui/traits/alias/self-in-const-generics.stderr b/tests/ui/traits/alias/self-in-const-generics.stderr
index 3de31b64c8b..3c799492591 100644
--- a/tests/ui/traits/alias/self-in-const-generics.stderr
+++ b/tests/ui/traits/alias/self-in-const-generics.stderr
@@ -1,10 +1,21 @@
-error[E0038]: the trait alias `BB` cannot be made into an object
+error[E0038]: the trait alias `BB` is not dyn compatible
   --> $DIR/self-in-const-generics.rs:9:16
    |
 LL | fn foo(x: &dyn BB) {}
-   |                ^^
+   |                ^^ `BB` is not dyn compatible
    |
-   = note: it cannot use `Self` as a type parameter in a supertrait or `where`-clause
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/self-in-const-generics.rs:7:12
+   |
+LL | trait BB = Bar<{ 2 + 1 }>;
+   |       --   ^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter
+   |       |
+   |       this trait is not dyn compatible...
+help: consider using an opaque type instead
+   |
+LL | fn foo(x: &impl BB) {}
+   |            ~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/traits/alias/self-in-generics.rs b/tests/ui/traits/alias/self-in-generics.rs
index 433b741532d..53752d9cede 100644
--- a/tests/ui/traits/alias/self-in-generics.rs
+++ b/tests/ui/traits/alias/self-in-generics.rs
@@ -6,6 +6,6 @@
 pub trait SelfInput = Fn(&mut Self);
 
 pub fn f(_f: &dyn SelfInput) {}
-//~^ ERROR the trait alias `SelfInput` cannot be made into an object [E0038]
+//~^ ERROR the trait alias `SelfInput` is not dyn compatible [E0038]
 
 fn main() {}
diff --git a/tests/ui/traits/alias/self-in-generics.stderr b/tests/ui/traits/alias/self-in-generics.stderr
index ffc0a00ad7d..5639b2b44a1 100644
--- a/tests/ui/traits/alias/self-in-generics.stderr
+++ b/tests/ui/traits/alias/self-in-generics.stderr
@@ -1,10 +1,23 @@
-error[E0038]: the trait alias `SelfInput` cannot be made into an object
+error[E0038]: the trait alias `SelfInput` is not dyn compatible
   --> $DIR/self-in-generics.rs:8:19
    |
 LL | pub fn f(_f: &dyn SelfInput) {}
-   |                   ^^^^^^^^^
+   |                   ^^^^^^^^^ `SelfInput` is not dyn compatible
    |
-   = note: it cannot use `Self` as a type parameter in a supertrait or `where`-clause
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/self-in-generics.rs:6:23
+   |
+LL | pub trait SelfInput = Fn(&mut Self);
+   |           ---------   ^^^^^^^^^^^^^
+   |           |           |
+   |           |           ...because it uses `Self` as a type parameter
+   |           |           ...because it uses `Self` as a type parameter
+   |           this trait is not dyn compatible...
+help: consider using an opaque type instead
+   |
+LL | pub fn f(_f: &impl SelfInput) {}
+   |               ~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/traits/bad-sized.stderr b/tests/ui/traits/bad-sized.stderr
index 0e82867ef03..21718cf0951 100644
--- a/tests/ui/traits/bad-sized.stderr
+++ b/tests/ui/traits/bad-sized.stderr
@@ -1,12 +1,12 @@
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/bad-sized.rs:4:28
+  --> $DIR/bad-sized.rs:4:20
    |
 LL |     let x: Vec<dyn Trait + Sized> = Vec::new();
-   |                    -----   ^^^^^ additional non-auto trait
+   |                    ^^^^^   ----- first non-auto trait
    |                    |
-   |                    first non-auto trait
+   |                    additional non-auto trait
    |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Trait + Sized {}`
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Sized + Trait {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/traits/issue-20692.rs b/tests/ui/traits/issue-20692.rs
index 1cb2d8c7302..10611a232f7 100644
--- a/tests/ui/traits/issue-20692.rs
+++ b/tests/ui/traits/issue-20692.rs
@@ -2,10 +2,10 @@ trait Array: Sized + Copy {}
 
 fn f<T: Array>(x: &T) {
     let _ = x
-    //~^ ERROR `Array` cannot be made into an object
+    //~^ ERROR `Array` is not dyn compatible
     as
     &dyn Array;
-    //~^ ERROR `Array` cannot be made into an object
+    //~^ ERROR `Array` is not dyn compatible
 }
 
 fn main() {}
diff --git a/tests/ui/traits/issue-20692.stderr b/tests/ui/traits/issue-20692.stderr
index 5e6a967fdc4..50ea7cde961 100644
--- a/tests/ui/traits/issue-20692.stderr
+++ b/tests/ui/traits/issue-20692.stderr
@@ -1,32 +1,34 @@
-error[E0038]: the trait `Array` cannot be made into an object
+error[E0038]: the trait `Array` is not dyn compatible
   --> $DIR/issue-20692.rs:7:5
    |
 LL |     &dyn Array;
-   |     ^^^^^^^^^^ `Array` cannot be made into an object
+   |     ^^^^^^^^^^ `Array` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-20692.rs:1:14
    |
 LL | trait Array: Sized + Copy {}
    |       -----  ^^^^^   ^^^^ ...because it requires `Self: Sized`
    |       |      |
    |       |      ...because it requires `Self: Sized`
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
 
-error[E0038]: the trait `Array` cannot be made into an object
+error[E0038]: the trait `Array` is not dyn compatible
   --> $DIR/issue-20692.rs:4:13
    |
 LL |     let _ = x
-   |             ^ `Array` cannot be made into an object
+   |             ^ `Array` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-20692.rs:1:14
    |
 LL | trait Array: Sized + Copy {}
    |       -----  ^^^^^   ^^^^ ...because it requires `Self: Sized`
    |       |      |
    |       |      ...because it requires `Self: Sized`
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
    = note: required for the cast from `&T` to `&dyn Array`
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/traits/issue-28576.rs b/tests/ui/traits/issue-28576.rs
index e19bd263581..fd026044401 100644
--- a/tests/ui/traits/issue-28576.rs
+++ b/tests/ui/traits/issue-28576.rs
@@ -6,7 +6,7 @@ pub trait Bar: Foo<Assoc=()> {
     //~^ ERROR: the size for values of type `Self` cannot be known
     //~| ERROR: the size for values of type `Self` cannot be known
     fn new(&self, b: &
-           dyn Bar //~ ERROR the trait `Bar` cannot be made into an object
+           dyn Bar //~ ERROR the trait `Bar` is not dyn compatible
               <Assoc=()>
     );
 }
diff --git a/tests/ui/traits/issue-28576.stderr b/tests/ui/traits/issue-28576.stderr
index 23581f2ee51..ba113d573d6 100644
--- a/tests/ui/traits/issue-28576.stderr
+++ b/tests/ui/traits/issue-28576.stderr
@@ -18,14 +18,16 @@ help: consider relaxing the implicit `Sized` restriction
 LL | pub trait Foo<RHS: ?Sized=Self> {
    |                  ++++++++
 
-error[E0038]: the trait `Bar` cannot be made into an object
-  --> $DIR/issue-28576.rs:9:12
+error[E0038]: the trait `Bar` is not dyn compatible
+  --> $DIR/issue-28576.rs:9:16
    |
-LL | /            dyn Bar
+LL |              dyn Bar
+   |  ________________^
 LL | |               <Assoc=()>
-   | |________________________^ `Bar` cannot be made into an object
+   | |________________________^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-28576.rs:5:16
    |
 LL | pub trait Bar: Foo<Assoc=()> {
@@ -33,7 +35,7 @@ LL | pub trait Bar: Foo<Assoc=()> {
    |           |    |   |
    |           |    |   ...because it uses `Self` as a type parameter
    |           |    ...because it uses `Self` as a type parameter
-   |           this trait cannot be made into an object...
+   |           this trait is not dyn compatible...
 help: consider using an opaque type instead
    |
 LL |            impl Bar
diff --git a/tests/ui/traits/issue-38404.rs b/tests/ui/traits/issue-38404.rs
index 9b60116f733..36da594c015 100644
--- a/tests/ui/traits/issue-38404.rs
+++ b/tests/ui/traits/issue-38404.rs
@@ -1,8 +1,8 @@
 trait A<T>: std::ops::Add<Self> + Sized {}
 trait B<T>: A<T> {}
 trait C<T>: A<dyn B<T, Output = usize>> {}
-//~^ ERROR the trait `B` cannot be made into an object
-//~| ERROR the trait `B` cannot be made into an object
-//~| ERROR the trait `B` cannot be made into an object
+//~^ ERROR the trait `B` is not dyn compatible
+//~| ERROR the trait `B` is not dyn compatible
+//~| ERROR the trait `B` is not dyn compatible
 
 fn main() {}
diff --git a/tests/ui/traits/issue-38404.stderr b/tests/ui/traits/issue-38404.stderr
index 145eeb88dd5..f9e592255dd 100644
--- a/tests/ui/traits/issue-38404.stderr
+++ b/tests/ui/traits/issue-38404.stderr
@@ -1,45 +1,48 @@
-error[E0038]: the trait `B` cannot be made into an object
-  --> $DIR/issue-38404.rs:3:15
+error[E0038]: the trait `B` is not dyn compatible
+  --> $DIR/issue-38404.rs:3:19
    |
 LL | trait C<T>: A<dyn B<T, Output = usize>> {}
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^ `B` cannot be made into an object
+   |                   ^^^^^^^^^^^^^^^^^^^^ `B` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-38404.rs:1:13
    |
 LL | trait A<T>: std::ops::Add<Self> + Sized {}
    |             ^^^^^^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter
 LL | trait B<T>: A<T> {}
-   |       - this trait cannot be made into an object...
+   |       - this trait is not dyn compatible...
 
-error[E0038]: the trait `B` cannot be made into an object
-  --> $DIR/issue-38404.rs:3:15
+error[E0038]: the trait `B` is not dyn compatible
+  --> $DIR/issue-38404.rs:3:19
    |
 LL | trait C<T>: A<dyn B<T, Output = usize>> {}
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^ `B` cannot be made into an object
+   |                   ^^^^^^^^^^^^^^^^^^^^ `B` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-38404.rs:1:13
    |
 LL | trait A<T>: std::ops::Add<Self> + Sized {}
    |             ^^^^^^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter
 LL | trait B<T>: A<T> {}
-   |       - this trait cannot be made into an object...
+   |       - this trait is not dyn compatible...
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0038]: the trait `B` cannot be made into an object
-  --> $DIR/issue-38404.rs:3:15
+error[E0038]: the trait `B` is not dyn compatible
+  --> $DIR/issue-38404.rs:3:19
    |
 LL | trait C<T>: A<dyn B<T, Output = usize>> {}
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^ `B` cannot be made into an object
+   |                   ^^^^^^^^^^^^^^^^^^^^ `B` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-38404.rs:1:13
    |
 LL | trait A<T>: std::ops::Add<Self> + Sized {}
    |             ^^^^^^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter
 LL | trait B<T>: A<T> {}
-   |       - this trait cannot be made into an object...
+   |       - this trait is not dyn compatible...
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/traits/issue-38604.rs b/tests/ui/traits/issue-38604.rs
index 002a3c43fcb..d90aa61ef9f 100644
--- a/tests/ui/traits/issue-38604.rs
+++ b/tests/ui/traits/issue-38604.rs
@@ -11,6 +11,6 @@ impl Foo for () {
 }
 
 fn main() {
-    let _f: Box<dyn Foo> = //~ ERROR `Foo` cannot be made into an object
-        Box::new(()); //~ ERROR `Foo` cannot be made into an object
+    let _f: Box<dyn Foo> = //~ ERROR `Foo` is not dyn compatible
+        Box::new(()); //~ ERROR `Foo` is not dyn compatible
 }
diff --git a/tests/ui/traits/issue-38604.stderr b/tests/ui/traits/issue-38604.stderr
index 5c788b0c85d..94f9c1540ad 100644
--- a/tests/ui/traits/issue-38604.stderr
+++ b/tests/ui/traits/issue-38604.stderr
@@ -1,32 +1,34 @@
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/issue-38604.rs:14:13
    |
 LL |     let _f: Box<dyn Foo> =
-   |             ^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |             ^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-38604.rs:2:22
    |
 LL | trait Foo where u32: Q<Self> {
    |       ---            ^^^^^^^ ...because it uses `Self` as a type parameter
    |       |
-   |       this trait cannot be made into an object...
-   = help: only type `()` implements the trait, consider using it directly instead
+   |       this trait is not dyn compatible...
+   = help: only type `()` implements `Foo`; consider using it directly instead.
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/issue-38604.rs:15:9
    |
 LL |         Box::new(());
-   |         ^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |         ^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-38604.rs:2:22
    |
 LL | trait Foo where u32: Q<Self> {
    |       ---            ^^^^^^^ ...because it uses `Self` as a type parameter
    |       |
-   |       this trait cannot be made into an object...
-   = help: only type `()` implements the trait, consider using it directly instead
+   |       this trait is not dyn compatible...
+   = help: only type `()` implements `Foo`; consider using it directly instead.
    = note: required for the cast from `Box<()>` to `Box<dyn Foo>`
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/traits/issue-72410.rs b/tests/ui/traits/issue-72410.rs
index c95f1dfdca5..df3738e2730 100644
--- a/tests/ui/traits/issue-72410.rs
+++ b/tests/ui/traits/issue-72410.rs
@@ -12,7 +12,7 @@ pub trait Foo {
 pub trait Bar {
     fn map()
     where for<'a> &'a mut [dyn Bar]: ;
-    //~^ ERROR: the trait `Bar` cannot be made into an object
+    //~^ ERROR: the trait `Bar` is not dyn compatible
 }
 
 fn main() {}
diff --git a/tests/ui/traits/issue-72410.stderr b/tests/ui/traits/issue-72410.stderr
index 6d56a198fc1..002345bff84 100644
--- a/tests/ui/traits/issue-72410.stderr
+++ b/tests/ui/traits/issue-72410.stderr
@@ -1,14 +1,15 @@
-error[E0038]: the trait `Bar` cannot be made into an object
+error[E0038]: the trait `Bar` is not dyn compatible
   --> $DIR/issue-72410.rs:14:19
    |
 LL |     where for<'a> &'a mut [dyn Bar]: ;
-   |                   ^^^^^^^^^^^^^^^^^ `Bar` cannot be made into an object
+   |                   ^^^^^^^^^^^^^^^^^ `Bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-72410.rs:13:8
    |
 LL | pub trait Bar {
-   |           --- this trait cannot be made into an object...
+   |           --- this trait is not dyn compatible...
 LL |     fn map()
    |        ^^^ ...because associated function `map` has no `self` parameter
 help: consider turning `map` into a method by giving it a `&self` argument
diff --git a/tests/ui/traits/item-privacy.rs b/tests/ui/traits/item-privacy.rs
index a3e1a22e7a8..f5c741ccaa5 100644
--- a/tests/ui/traits/item-privacy.rs
+++ b/tests/ui/traits/item-privacy.rs
@@ -99,8 +99,8 @@ fn check_assoc_const() {
     S::C; // OK
     // A, B, C are resolved as inherent items, their traits don't need to be in scope
     <dyn C>::A; //~ ERROR associated constant `A` is private
-                //~^ ERROR the trait `assoc_const::C` cannot be made into an object
-    <dyn C>::B; // ERROR the trait `assoc_const::C` cannot be made into an object
+                //~^ ERROR the trait `assoc_const::C` is not dyn compatible
+    <dyn C>::B; // ERROR the trait `assoc_const::C` is not dyn compatible
     C::C; // OK
 }
 
diff --git a/tests/ui/traits/item-privacy.stderr b/tests/ui/traits/item-privacy.stderr
index c20d2f723c5..c97158a5b76 100644
--- a/tests/ui/traits/item-privacy.stderr
+++ b/tests/ui/traits/item-privacy.stderr
@@ -136,13 +136,14 @@ LL |         const A: u8 = 0;
 LL |     <dyn C>::A;
    |              ^ private associated constant
 
-error[E0038]: the trait `assoc_const::C` cannot be made into an object
+error[E0038]: the trait `assoc_const::C` is not dyn compatible
   --> $DIR/item-privacy.rs:101:6
    |
 LL |     <dyn C>::A;
-   |      ^^^^^ `assoc_const::C` cannot be made into an object
+   |      ^^^^^ `assoc_const::C` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/item-privacy.rs:25:15
    |
 LL |         const A: u8 = 0;
@@ -152,13 +153,13 @@ LL |         const B: u8 = 0;
    |               ^ ...because it contains this associated `const`
 ...
 LL |     pub trait C: A + B {
-   |               - this trait cannot be made into an object...
+   |               - this trait is not dyn compatible...
 LL |         const C: u8 = 0;
    |               ^ ...because it contains this associated `const`
    = help: consider moving `C` to another trait
    = help: consider moving `A` to another trait
    = help: consider moving `B` to another trait
-   = help: only type `S` implements the trait, consider using it directly instead
+   = help: only type `S` implements `assoc_const::C`; consider using it directly instead.
 
 error[E0223]: ambiguous associated type
   --> $DIR/item-privacy.rs:115:12
diff --git a/tests/ui/traits/missing-for-type-in-impl.e2015.stderr b/tests/ui/traits/missing-for-type-in-impl.e2015.stderr
index 541b49b024f..682d18842b8 100644
--- a/tests/ui/traits/missing-for-type-in-impl.e2015.stderr
+++ b/tests/ui/traits/missing-for-type-in-impl.e2015.stderr
@@ -34,17 +34,18 @@ help: you might have intended to implement this trait for a given type
 LL | impl Foo<i64> for /* Type */ {
    |               ++++++++++++++
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/missing-for-type-in-impl.rs:8:6
    |
 LL | impl Foo<i64> {
-   |      ^^^^^^^^ `Foo` cannot be made into an object
+   |      ^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/missing-for-type-in-impl.rs:4:8
    |
 LL | trait Foo<T> {
-   |       --- this trait cannot be made into an object...
+   |       --- this trait is not dyn compatible...
 LL |     fn id(me: T) -> T;
    |        ^^ ...because associated function `id` has no `self` parameter
 help: consider turning `id` into a method by giving it a `&self` argument
diff --git a/tests/ui/traits/missing-for-type-in-impl.rs b/tests/ui/traits/missing-for-type-in-impl.rs
index e5dd3651609..e8163954274 100644
--- a/tests/ui/traits/missing-for-type-in-impl.rs
+++ b/tests/ui/traits/missing-for-type-in-impl.rs
@@ -11,7 +11,7 @@ impl Foo<i64> {
 //[e2015]~| WARNING trait objects without an explicit `dyn` are deprecated
 //[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
 //[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
-//[e2015]~| ERROR the trait `Foo` cannot be made into an object
+//[e2015]~| ERROR the trait `Foo` is not dyn compatible
     fn id(me: i64) -> i64 {me}
 }
 
diff --git a/tests/ui/traits/next-solver/diagnostics/alias_relate_error_uses_structurally_normalize.rs b/tests/ui/traits/next-solver/diagnostics/alias_relate_error_uses_structurally_normalize.rs
new file mode 100644
index 00000000000..5cea9bb74d7
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/alias_relate_error_uses_structurally_normalize.rs
@@ -0,0 +1,28 @@
+//@ compile-flags: -Znext-solver
+
+// When encountering a fulfillment error from an `alias-relate` goal failing, we
+// would previously manually construct a `normalizes-to` goal involving the alias
+// and an infer var. This would then ICE as normalization would return a nested
+// goal (the `T: Sized` from the `Trait` impl for `Foo<T>` below) from the root goal
+// which is not supported.
+
+struct Foo<T>(T);
+
+trait Trait {
+    type Assoc;
+}
+
+// `T: Sized` being explicit is not required, but the bound being present *is*.
+impl<T: Sized> Trait for Foo<T> {
+    type Assoc = u64;
+}
+
+fn bar<T: Trait<Assoc = u32>>(_: T) {}
+
+fn main() {
+    let foo = Foo(Default::default());
+    bar(foo);
+    //~^ ERROR: type mismatch resolving `<Foo<_> as Trait>::Assoc == u32`
+    // Here diagnostics would manually construct a `<Foo<?y> as Trait>::Assoc normalizes-to ?x` goal
+    // which would return a nested goal of `?y: Sized` from the impl.
+}
diff --git a/tests/ui/traits/next-solver/diagnostics/alias_relate_error_uses_structurally_normalize.stderr b/tests/ui/traits/next-solver/diagnostics/alias_relate_error_uses_structurally_normalize.stderr
new file mode 100644
index 00000000000..ff3cbdb2c78
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/alias_relate_error_uses_structurally_normalize.stderr
@@ -0,0 +1,17 @@
+error[E0271]: type mismatch resolving `<Foo<_> as Trait>::Assoc == u32`
+  --> $DIR/alias_relate_error_uses_structurally_normalize.rs:24:9
+   |
+LL |     bar(foo);
+   |     --- ^^^ expected `u32`, found `u64`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `bar`
+  --> $DIR/alias_relate_error_uses_structurally_normalize.rs:20:17
+   |
+LL | fn bar<T: Trait<Assoc = u32>>(_: T) {}
+   |                 ^^^^^^^^^^^ required by this bound in `bar`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.current.stderr b/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.current.stderr
new file mode 100644
index 00000000000..a863886181c
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.current.stderr
@@ -0,0 +1,17 @@
+error[E0277]: the trait bound `Foo: Trait` is not satisfied
+  --> $DIR/dont-pick-fnptr-bound-as-leaf.rs:24:20
+   |
+LL |     requires_trait(Foo);
+   |     -------------- ^^^ the trait `Trait` is not implemented for `Foo`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `requires_trait`
+  --> $DIR/dont-pick-fnptr-bound-as-leaf.rs:19:22
+   |
+LL | fn requires_trait<T: Trait>(_: T) {}
+   |                      ^^^^^ required by this bound in `requires_trait`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.next.stderr b/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.next.stderr
new file mode 100644
index 00000000000..a863886181c
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.next.stderr
@@ -0,0 +1,17 @@
+error[E0277]: the trait bound `Foo: Trait` is not satisfied
+  --> $DIR/dont-pick-fnptr-bound-as-leaf.rs:24:20
+   |
+LL |     requires_trait(Foo);
+   |     -------------- ^^^ the trait `Trait` is not implemented for `Foo`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `requires_trait`
+  --> $DIR/dont-pick-fnptr-bound-as-leaf.rs:19:22
+   |
+LL | fn requires_trait<T: Trait>(_: T) {}
+   |                      ^^^^^ required by this bound in `requires_trait`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.rs b/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.rs
new file mode 100644
index 00000000000..995f2c9fbee
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.rs
@@ -0,0 +1,28 @@
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+
+// When emitting an error for `Foo: Trait` not holding we attempt to find a nested goal
+// to give as the reason why the bound does not hold. This test checks that we do not
+// try to tell the user that `Foo: FnPtr` is unimplemented as that would be confusing.
+
+#![feature(fn_ptr_trait)]
+
+use std::marker::FnPtr;
+
+trait Trait {}
+
+impl<T: FnPtr> Trait for T {}
+
+struct Foo;
+
+fn requires_trait<T: Trait>(_: T) {}
+//~^ NOTE: required by a bound in `requires_trait`
+//~| NOTE: required by this bound in `requires_trait`
+
+fn main() {
+    requires_trait(Foo);
+    //~^ ERROR: the trait bound `Foo: Trait` is not satisfied
+    //~| NOTE: the trait `Trait` is not implemented for `Foo`
+    //~| NOTE: required by a bound introduced by this call
+}
diff --git a/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.rs b/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.rs
new file mode 100644
index 00000000000..d05def2cb75
--- /dev/null
+++ b/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.rs
@@ -0,0 +1,17 @@
+//@ compile-flags: -Znext-solver
+
+trait Wf {
+    type Assoc;
+}
+
+struct S {
+    f: &'static <() as Wf>::Assoc,
+    //~^ ERROR the trait bound `(): Wf` is not satisfied
+}
+
+fn main() {
+    let x: S = todo!();
+    let y: &() = x.f;
+    //~^ ERROR mismatched types
+    //~| ERROR the trait bound `(): Wf` is not satisfied
+}
diff --git a/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr b/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr
new file mode 100644
index 00000000000..32a7766a638
--- /dev/null
+++ b/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr
@@ -0,0 +1,39 @@
+error[E0277]: the trait bound `(): Wf` is not satisfied
+  --> $DIR/non-wf-in-coerce-pointers.rs:8:17
+   |
+LL |     f: &'static <() as Wf>::Assoc,
+   |                 ^^^^^^^^^^^^^^^^^ the trait `Wf` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/non-wf-in-coerce-pointers.rs:3:1
+   |
+LL | trait Wf {
+   | ^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/non-wf-in-coerce-pointers.rs:14:18
+   |
+LL |     let y: &() = x.f;
+   |            ---   ^^^ types differ
+   |            |
+   |            expected due to this
+   |
+   = note: expected reference `&()`
+              found reference `&'static <() as Wf>::Assoc`
+
+error[E0277]: the trait bound `(): Wf` is not satisfied
+  --> $DIR/non-wf-in-coerce-pointers.rs:14:18
+   |
+LL |     let y: &() = x.f;
+   |                  ^^^ the trait `Wf` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/non-wf-in-coerce-pointers.rs:3:1
+   |
+LL | trait Wf {
+   | ^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0277, E0308.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs b/tests/ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs
new file mode 100644
index 00000000000..dc96652f82f
--- /dev/null
+++ b/tests/ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs
@@ -0,0 +1,21 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+// `(): Trait` is a global where-bound with a projection bound.
+// This previously resulted in ambiguity as we considered both
+// the impl and the where-bound while normalizing.
+
+trait Trait {
+    type Assoc;
+}
+impl Trait for () {
+    type Assoc = &'static ();
+}
+
+fn foo<'a>(x: <() as Trait>::Assoc)
+where
+    (): Trait<Assoc = &'a ()>,
+{
+}
+
+fn main() {}
diff --git a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs
index a635edb4485..28785ae3dea 100644
--- a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs
+++ b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs
@@ -17,8 +17,8 @@ impl<T: ?Sized> Bar<T> for () {}
 
 fn main() {
     let x: &dyn Foo = &();
-    //~^ ERROR the trait `Foo` cannot be made into an object
-    //~| ERROR the trait `Foo` cannot be made into an object
+    //~^ ERROR the trait `Foo` is not dyn compatible
+    //~| ERROR the trait `Foo` is not dyn compatible
     needs_bar(x);
-    //~^ ERROR the trait `Foo` cannot be made into an object
+    //~^ ERROR the trait `Foo` is not dyn compatible
 }
diff --git a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr
index dd2dca74f90..8448890c084 100644
--- a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr
+++ b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr
@@ -7,51 +7,54 @@ LL | #![feature(non_lifetime_binders)]
    = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/supertrait-dyn-compatibility.rs:19:23
    |
 LL |     let x: &dyn Foo = &();
-   |                       ^^^ `Foo` cannot be made into an object
+   |                       ^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/supertrait-dyn-compatibility.rs:4:12
    |
 LL | trait Foo: for<T> Bar<T> {}
    |       ---  ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables
    |       |
-   |       this trait cannot be made into an object...
-   = help: only type `()` implements the trait, consider using it directly instead
+   |       this trait is not dyn compatible...
+   = help: only type `()` implements `Foo`; consider using it directly instead.
    = note: required for the cast from `&()` to `&dyn Foo`
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/supertrait-dyn-compatibility.rs:19:12
    |
 LL |     let x: &dyn Foo = &();
-   |            ^^^^^^^^ `Foo` cannot be made into an object
+   |            ^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/supertrait-dyn-compatibility.rs:4:12
    |
 LL | trait Foo: for<T> Bar<T> {}
    |       ---  ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables
    |       |
-   |       this trait cannot be made into an object...
-   = help: only type `()` implements the trait, consider using it directly instead
+   |       this trait is not dyn compatible...
+   = help: only type `()` implements `Foo`; consider using it directly instead.
 
-error[E0038]: the trait `Foo` cannot be made into an object
+error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/supertrait-dyn-compatibility.rs:22:5
    |
 LL |     needs_bar(x);
-   |     ^^^^^^^^^ `Foo` cannot be made into an object
+   |     ^^^^^^^^^ `Foo` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/supertrait-dyn-compatibility.rs:4:12
    |
 LL | trait Foo: for<T> Bar<T> {}
    |       ---  ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables
    |       |
-   |       this trait cannot be made into an object...
-   = help: only type `()` implements the trait, consider using it directly instead
+   |       this trait is not dyn compatible...
+   = help: only type `()` implements `Foo`; consider using it directly instead.
 
 error: aborting due to 3 previous errors; 1 warning emitted
 
diff --git a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs
index 4aadd45c49c..6dcfc754448 100644
--- a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs
+++ b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs
@@ -8,9 +8,8 @@ trait Try {
 
 fn w<'a, T: 'a, F: Fn(&'a T)>() {
     let b: &dyn FromResidual = &();
-    //~^ ERROR: the trait `FromResidual` cannot be made into an object
-    //~| ERROR: the trait `FromResidual` cannot be made into an object
-    //~| ERROR: the trait `FromResidual` cannot be made into an object
+    //~^ ERROR: the trait `FromResidual` is not dyn compatible
+    //~| ERROR: the trait `FromResidual` is not dyn compatible
 }
 
 fn main() {}
diff --git a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr
index c67a8c05379..7040c067f5c 100644
--- a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr
+++ b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr
@@ -1,22 +1,15 @@
-error[E0038]: the trait `FromResidual` cannot be made into an object
-  --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:10:17
-   |
-LL |     let b: &dyn FromResidual = &();
-   |                 ^^^^^^^^^^^^
-   |
-   = note: it cannot use `Self` as a type parameter in a supertrait or `where`-clause
-
-error[E0038]: the trait `FromResidual` cannot be made into an object
+error[E0038]: the trait `FromResidual` is not dyn compatible
   --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:10:32
    |
 LL |     let b: &dyn FromResidual = &();
-   |                                ^^^ `FromResidual` cannot be made into an object
+   |                                ^^^ `FromResidual` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:2:8
    |
 LL | trait FromResidual<R = <Self as Try>::Residual> {
-   |       ------------ this trait cannot be made into an object...
+   |       ------------ this trait is not dyn compatible...
 LL |     fn from_residual(residual: R) -> Self;
    |        ^^^^^^^^^^^^^ ...because associated function `from_residual` has no `self` parameter
    = note: required for the cast from `&()` to `&dyn FromResidual<{type error}>`
@@ -29,17 +22,18 @@ help: alternatively, consider constraining `from_residual` so it does not apply
 LL |     fn from_residual(residual: R) -> Self where Self: Sized;
    |                                           +++++++++++++++++
 
-error[E0038]: the trait `FromResidual` cannot be made into an object
+error[E0038]: the trait `FromResidual` is not dyn compatible
   --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:10:12
    |
 LL |     let b: &dyn FromResidual = &();
-   |            ^^^^^^^^^^^^^^^^^ `FromResidual` cannot be made into an object
+   |            ^^^^^^^^^^^^^^^^^ `FromResidual` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:2:8
    |
 LL | trait FromResidual<R = <Self as Try>::Residual> {
-   |       ------------ this trait cannot be made into an object...
+   |       ------------ this trait is not dyn compatible...
 LL |     fn from_residual(residual: R) -> Self;
    |        ^^^^^^^^^^^^^ ...because associated function `from_residual` has no `self` parameter
 help: consider turning `from_residual` into a method by giving it a `&self` argument
@@ -51,6 +45,6 @@ help: alternatively, consider constraining `from_residual` so it does not apply
 LL |     fn from_residual(residual: R) -> Self where Self: Sized;
    |                                           +++++++++++++++++
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/traits/object/macro-matcher.rs b/tests/ui/traits/object/macro-matcher.rs
index 91097874997..675d9f51532 100644
--- a/tests/ui/traits/object/macro-matcher.rs
+++ b/tests/ui/traits/object/macro-matcher.rs
@@ -6,7 +6,7 @@ macro_rules! m {
 
 fn main() {
     m!(dyn Copy + Send + 'static);
-    //~^ ERROR the trait `Copy` cannot be made into an object
+    //~^ ERROR the trait `Copy` is not dyn compatible
     m!(dyn 'static + Send);
     m!(dyn 'static +); //~ ERROR at least one trait is required for an object type
 }
diff --git a/tests/ui/traits/object/macro-matcher.stderr b/tests/ui/traits/object/macro-matcher.stderr
index 7924c86e294..ab0fc213c9f 100644
--- a/tests/ui/traits/object/macro-matcher.stderr
+++ b/tests/ui/traits/object/macro-matcher.stderr
@@ -4,14 +4,15 @@ error[E0224]: at least one trait is required for an object type
 LL |     m!(dyn 'static +);
    |        ^^^^^^^^^^^^^
 
-error[E0038]: the trait `Copy` cannot be made into an object
+error[E0038]: the trait `Copy` is not dyn compatible
   --> $DIR/macro-matcher.rs:8:8
    |
 LL |     m!(dyn Copy + Send + 'static);
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^ `Copy` cannot be made into an object
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^ `Copy` is not dyn compatible
    |
-   = note: the trait cannot be made into an object because it requires `Self: Sized`
-   = note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+   = note: the trait is not dyn compatible because it requires `Self: Sized`
+   = note: for a trait to be dyn compatible it needs to allow building a vtable
+           for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/traits/object/safety.stderr b/tests/ui/traits/object/safety.stderr
index a2cb656b08d..eab59f39c28 100644
--- a/tests/ui/traits/object/safety.stderr
+++ b/tests/ui/traits/object/safety.stderr
@@ -1,17 +1,18 @@
-error[E0038]: the trait `Tr` cannot be made into an object
+error[E0038]: the trait `Tr` is not dyn compatible
   --> $DIR/safety.rs:15:22
    |
 LL |     let _: &dyn Tr = &St;
-   |                      ^^^ `Tr` cannot be made into an object
+   |                      ^^^ `Tr` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/safety.rs:4:8
    |
 LL | trait Tr {
-   |       -- this trait cannot be made into an object...
+   |       -- this trait is not dyn compatible...
 LL |     fn foo();
    |        ^^^ ...because associated function `foo` has no `self` parameter
-   = help: only type `St` implements the trait, consider using it directly instead
+   = help: only type `St` implements `Tr`; consider using it directly instead.
    = note: required for the cast from `&St` to `&dyn Tr`
 help: consider turning `foo` into a method by giving it a `&self` argument
    |
@@ -22,20 +23,21 @@ help: alternatively, consider constraining `foo` so it does not apply to trait o
 LL |     fn foo() where Self: Sized;
    |              +++++++++++++++++
 
-error[E0038]: the trait `Tr` cannot be made into an object
+error[E0038]: the trait `Tr` is not dyn compatible
   --> $DIR/safety.rs:15:12
    |
 LL |     let _: &dyn Tr = &St;
-   |            ^^^^^^^ `Tr` cannot be made into an object
+   |            ^^^^^^^ `Tr` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/safety.rs:4:8
    |
 LL | trait Tr {
-   |       -- this trait cannot be made into an object...
+   |       -- this trait is not dyn compatible...
 LL |     fn foo();
    |        ^^^ ...because associated function `foo` has no `self` parameter
-   = help: only type `St` implements the trait, consider using it directly instead
+   = help: only type `St` implements `Tr`; consider using it directly instead.
 help: consider turning `foo` into a method by giving it a `&self` argument
    |
 LL |     fn foo(&self);
diff --git a/tests/ui/traits/test-2.stderr b/tests/ui/traits/test-2.stderr
index 3da95b47844..8915e490b4d 100644
--- a/tests/ui/traits/test-2.stderr
+++ b/tests/ui/traits/test-2.stderr
@@ -26,65 +26,74 @@ note: method defined here, with 1 generic parameter: `X`
 LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
    |                                       ^^^^ -
 
-error[E0038]: the trait `bar` cannot be made into an object
+error[E0038]: the trait `bar` is not dyn compatible
   --> $DIR/test-2.rs:13:22
    |
 LL |     (Box::new(10) as Box<dyn bar>).dup();
-   |                      ^^^^^^^^^^^^ `bar` cannot be made into an object
+   |                      ^^^^^^^^^^^^ `bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/test-2.rs:4:30
    |
 LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
    |       ---                    ^^^^     ^^^^ ...because method `blah` has generic type parameters
    |       |                      |
    |       |                      ...because method `dup` references the `Self` type in its return type
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
    = help: consider moving `dup` to another trait
    = help: consider moving `blah` to another trait
-   = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `bar` for this new enum and using it instead:
+   = help: the following types implement `bar`:
              i32
              u32
+           consider defining an enum where each variant holds one of these types,
+           implementing `bar` for this new enum and using it instead
 
-error[E0038]: the trait `bar` cannot be made into an object
+error[E0038]: the trait `bar` is not dyn compatible
   --> $DIR/test-2.rs:13:5
    |
 LL |     (Box::new(10) as Box<dyn bar>).dup();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `bar` cannot be made into an object
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/test-2.rs:4:30
    |
 LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
    |       ---                    ^^^^     ^^^^ ...because method `blah` has generic type parameters
    |       |                      |
    |       |                      ...because method `dup` references the `Self` type in its return type
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
    = help: consider moving `dup` to another trait
    = help: consider moving `blah` to another trait
-   = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `bar` for this new enum and using it instead:
+   = help: the following types implement `bar`:
              i32
              u32
+           consider defining an enum where each variant holds one of these types,
+           implementing `bar` for this new enum and using it instead
 
-error[E0038]: the trait `bar` cannot be made into an object
+error[E0038]: the trait `bar` is not dyn compatible
   --> $DIR/test-2.rs:13:6
    |
 LL |     (Box::new(10) as Box<dyn bar>).dup();
-   |      ^^^^^^^^^^^^ `bar` cannot be made into an object
+   |      ^^^^^^^^^^^^ `bar` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/test-2.rs:4:30
    |
 LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
    |       ---                    ^^^^     ^^^^ ...because method `blah` has generic type parameters
    |       |                      |
    |       |                      ...because method `dup` references the `Self` type in its return type
-   |       this trait cannot be made into an object...
+   |       this trait is not dyn compatible...
    = help: consider moving `dup` to another trait
    = help: consider moving `blah` to another trait
-   = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `bar` for this new enum and using it instead:
+   = help: the following types implement `bar`:
              i32
              u32
+           consider defining an enum where each variant holds one of these types,
+           implementing `bar` for this new enum and using it instead
    = note: required for the cast from `Box<{integer}>` to `Box<dyn bar>`
 
 error: aborting due to 5 previous errors
diff --git a/tests/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr b/tests/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr
index 2d5bcf1fbc4..71717c6945e 100644
--- a/tests/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr
+++ b/tests/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr
@@ -10,21 +10,20 @@ help: consider using a box or reference as appropriate
 LL |     let y = x as dyn MyAdd<i32>;
    |             ^
 
-error[E0038]: the trait `MyAdd` cannot be made into an object
+error[E0038]: the trait `MyAdd` is not dyn compatible
   --> $DIR/type-parameter-defaults-referencing-Self-ppaux.rs:14:18
    |
 LL |     let y = x as dyn MyAdd<i32>;
-   |                  ^^^^^^^^^^^^^^ `MyAdd` cannot be made into an object
+   |                  ^^^^^^^^^^^^^^ `MyAdd` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/type-parameter-defaults-referencing-Self-ppaux.rs:6:55
    |
 LL | trait MyAdd<Rhs=Self> { fn add(&self, other: &Rhs) -> Self; }
-   |       -----                                           ^^^^ ...because method `add` references the `Self` type in its return type
-   |       |
-   |       this trait cannot be made into an object...
+   |       ----- this trait is not dyn compatible...       ^^^^ ...because method `add` references the `Self` type in its return type
    = help: consider moving `add` to another trait
-   = help: only type `i32` implements the trait, consider using it directly instead
+   = help: only type `i32` implements `MyAdd`; consider using it directly instead.
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/typeck/bad-index-due-to-nested.stderr b/tests/ui/typeck/bad-index-due-to-nested.current.stderr
index dd2ce092368..dc3d998c399 100644
--- a/tests/ui/typeck/bad-index-due-to-nested.stderr
+++ b/tests/ui/typeck/bad-index-due-to-nested.current.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `K: Hash` is not satisfied
-  --> $DIR/bad-index-due-to-nested.rs:20:5
+  --> $DIR/bad-index-due-to-nested.rs:24:5
    |
 LL |     map[k]
    |     ^^^ the trait `Hash` is not implemented for `K`
    |
 note: required for `HashMap<K, V>` to implement `Index<&K>`
-  --> $DIR/bad-index-due-to-nested.rs:7:12
+  --> $DIR/bad-index-due-to-nested.rs:11:12
    |
 LL | impl<K, V> Index<&K> for HashMap<K, V>
    |            ^^^^^^^^^     ^^^^^^^^^^^^^
@@ -18,13 +18,13 @@ LL | fn index<'a, K: std::hash::Hash, V>(map: &'a HashMap<K, V>, k: K) -> &'a V
    |               +++++++++++++++++
 
 error[E0277]: the trait bound `V: Copy` is not satisfied
-  --> $DIR/bad-index-due-to-nested.rs:20:5
+  --> $DIR/bad-index-due-to-nested.rs:24:5
    |
 LL |     map[k]
    |     ^^^ the trait `Copy` is not implemented for `V`
    |
 note: required for `HashMap<K, V>` to implement `Index<&K>`
-  --> $DIR/bad-index-due-to-nested.rs:7:12
+  --> $DIR/bad-index-due-to-nested.rs:11:12
    |
 LL | impl<K, V> Index<&K> for HashMap<K, V>
    |            ^^^^^^^^^     ^^^^^^^^^^^^^
@@ -37,7 +37,7 @@ LL | fn index<'a, K, V: std::marker::Copy>(map: &'a HashMap<K, V>, k: K) -> &'a
    |                  +++++++++++++++++++
 
 error[E0308]: mismatched types
-  --> $DIR/bad-index-due-to-nested.rs:20:9
+  --> $DIR/bad-index-due-to-nested.rs:24:9
    |
 LL | fn index<'a, K, V>(map: &'a HashMap<K, V>, k: K) -> &'a V {
    |              - found this type parameter
@@ -52,7 +52,7 @@ LL |     map[&k]
    |         +
 
 error[E0308]: mismatched types
-  --> $DIR/bad-index-due-to-nested.rs:20:5
+  --> $DIR/bad-index-due-to-nested.rs:24:5
    |
 LL | fn index<'a, K, V>(map: &'a HashMap<K, V>, k: K) -> &'a V {
    |                 - found this type parameter         ----- expected `&'a V` because of return type
diff --git a/tests/ui/typeck/bad-index-due-to-nested.next.stderr b/tests/ui/typeck/bad-index-due-to-nested.next.stderr
new file mode 100644
index 00000000000..a0b275b7852
--- /dev/null
+++ b/tests/ui/typeck/bad-index-due-to-nested.next.stderr
@@ -0,0 +1,76 @@
+error[E0277]: the trait bound `K: Hash` is not satisfied
+  --> $DIR/bad-index-due-to-nested.rs:24:5
+   |
+LL |     map[k]
+   |     ^^^ the trait `Hash` is not implemented for `K`
+   |
+note: required for `HashMap<K, V>` to implement `Index<&K>`
+  --> $DIR/bad-index-due-to-nested.rs:11:12
+   |
+LL | impl<K, V> Index<&K> for HashMap<K, V>
+   |            ^^^^^^^^^     ^^^^^^^^^^^^^
+LL | where
+LL |     K: Hash,
+   |        ---- unsatisfied trait bound introduced here
+help: consider restricting type parameter `K` with trait `Hash`
+   |
+LL | fn index<'a, K: std::hash::Hash, V>(map: &'a HashMap<K, V>, k: K) -> &'a V {
+   |               +++++++++++++++++
+
+error[E0277]: the trait bound `V: Copy` is not satisfied
+  --> $DIR/bad-index-due-to-nested.rs:24:5
+   |
+LL |     map[k]
+   |     ^^^ the trait `Copy` is not implemented for `V`
+   |
+note: required for `HashMap<K, V>` to implement `Index<&K>`
+  --> $DIR/bad-index-due-to-nested.rs:11:12
+   |
+LL | impl<K, V> Index<&K> for HashMap<K, V>
+   |            ^^^^^^^^^     ^^^^^^^^^^^^^
+...
+LL |     V: Copy,
+   |        ---- unsatisfied trait bound introduced here
+help: consider restricting type parameter `V` with trait `Copy`
+   |
+LL | fn index<'a, K, V: std::marker::Copy>(map: &'a HashMap<K, V>, k: K) -> &'a V {
+   |                  +++++++++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/bad-index-due-to-nested.rs:24:9
+   |
+LL | fn index<'a, K, V>(map: &'a HashMap<K, V>, k: K) -> &'a V {
+   |              - found this type parameter
+LL |     map[k]
+   |         ^ expected `&K`, found type parameter `K`
+   |
+   = note:   expected reference `&_`
+           found type parameter `_`
+help: consider borrowing here
+   |
+LL |     map[&k]
+   |         +
+
+error[E0277]: the trait bound `K: Hash` is not satisfied
+  --> $DIR/bad-index-due-to-nested.rs:24:5
+   |
+LL |     map[k]
+   |     ^^^^^^ the trait `Hash` is not implemented for `K`
+   |
+note: required for `HashMap<K, V>` to implement `Index<&K>`
+  --> $DIR/bad-index-due-to-nested.rs:11:12
+   |
+LL | impl<K, V> Index<&K> for HashMap<K, V>
+   |            ^^^^^^^^^     ^^^^^^^^^^^^^
+LL | where
+LL |     K: Hash,
+   |        ---- unsatisfied trait bound introduced here
+help: consider restricting type parameter `K` with trait `Hash`
+   |
+LL | fn index<'a, K: std::hash::Hash, V>(map: &'a HashMap<K, V>, k: K) -> &'a V {
+   |               +++++++++++++++++
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0277, E0308.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/typeck/bad-index-due-to-nested.rs b/tests/ui/typeck/bad-index-due-to-nested.rs
index 2564b530004..e7f385865af 100644
--- a/tests/ui/typeck/bad-index-due-to-nested.rs
+++ b/tests/ui/typeck/bad-index-due-to-nested.rs
@@ -1,3 +1,7 @@
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+
 use std::hash::Hash;
 use std::marker::PhantomData;
 use std::ops::Index;
@@ -21,7 +25,8 @@ fn index<'a, K, V>(map: &'a HashMap<K, V>, k: K) -> &'a V {
     //~^ ERROR the trait bound `K: Hash` is not satisfied
     //~| ERROR the trait bound `V: Copy` is not satisfied
     //~| ERROR mismatched types
-    //~| ERROR mismatched types
+    //[current]~| ERROR mismatched types
+    //[next]~^^^^^ ERROR the trait bound `K: Hash` is not satisfied
 }
 
 fn main() {}
diff --git a/tests/ui/typeck/issue-82772.stderr b/tests/ui/typeck/issue-82772.stderr
index 321143cb968..a314306137a 100644
--- a/tests/ui/typeck/issue-82772.stderr
+++ b/tests/ui/typeck/issue-82772.stderr
@@ -2,19 +2,19 @@ error[E0451]: field `0` of struct `Box` is private
   --> $DIR/issue-82772.rs:5:15
    |
 LL |     let Box { 0: _, .. }: Box<()>;
-   |               ^^^^ private field
+   |               ^ private field
 
 error[E0451]: field `1` of struct `Box` is private
   --> $DIR/issue-82772.rs:6:15
    |
 LL |     let Box { 1: _, .. }: Box<()>;
-   |               ^^^^ private field
+   |               ^ private field
 
 error[E0451]: field `1` of struct `ModPrivateStruct` is private
   --> $DIR/issue-82772.rs:7:28
    |
 LL |     let ModPrivateStruct { 1: _, .. } = ModPrivateStruct::default();
-   |                            ^^^^ private field
+   |                            ^ private field
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/union/union-derive-eq.stderr b/tests/ui/union/union-derive-eq.current.stderr
index b068edd6d69..151ceebe1ba 100644
--- a/tests/ui/union/union-derive-eq.stderr
+++ b/tests/ui/union/union-derive-eq.current.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `PartialEqNotEq: Eq` is not satisfied
-  --> $DIR/union-derive-eq.rs:13:5
+  --> $DIR/union-derive-eq.rs:21:5
    |
 LL | #[derive(Eq)]
    |          -- in this derive macro expansion
diff --git a/tests/ui/union/union-derive-eq.next.stderr b/tests/ui/union/union-derive-eq.next.stderr
new file mode 100644
index 00000000000..3952b1f1284
--- /dev/null
+++ b/tests/ui/union/union-derive-eq.next.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `PartialEqNotEq: Eq` is not satisfied
+  --> $DIR/union-derive-eq.rs:21:5
+   |
+LL | #[derive(Eq)]
+   |          -- in this derive macro expansion
+LL | union U2 {
+LL |     a: PartialEqNotEq,
+   |     ^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `PartialEqNotEq`
+   |
+   = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider annotating `PartialEqNotEq` with `#[derive(Eq)]`
+   |
+LL + #[derive(Eq)]
+LL | struct PartialEqNotEq;
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/union/union-derive-eq.rs b/tests/ui/union/union-derive-eq.rs
index e689f8c27d7..085262a72a1 100644
--- a/tests/ui/union/union-derive-eq.rs
+++ b/tests/ui/union/union-derive-eq.rs
@@ -1,9 +1,17 @@
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+
 #[derive(Eq)] // OK
 union U1 {
     a: u8,
 }
 
-impl PartialEq for U1 { fn eq(&self, rhs: &Self) -> bool { true } }
+impl PartialEq for U1 {
+    fn eq(&self, rhs: &Self) -> bool {
+        true
+    }
+}
 
 #[derive(PartialEq, Copy, Clone)]
 struct PartialEqNotEq;
@@ -13,6 +21,10 @@ union U2 {
     a: PartialEqNotEq, //~ ERROR the trait bound `PartialEqNotEq: Eq` is not satisfied
 }
 
-impl PartialEq for U2 { fn eq(&self, rhs: &Self) -> bool { true } }
+impl PartialEq for U2 {
+    fn eq(&self, rhs: &Self) -> bool {
+        true
+    }
+}
 
 fn main() {}
diff --git a/tests/ui/unpretty/staged-api-invalid-path-108697.stderr b/tests/ui/unpretty/staged-api-invalid-path-108697.stderr
index 9c6d1a042d7..e68e19c4dc9 100644
--- a/tests/ui/unpretty/staged-api-invalid-path-108697.stderr
+++ b/tests/ui/unpretty/staged-api-invalid-path-108697.stderr
@@ -1,4 +1,4 @@
-error: couldn't read $DIR/lol: No such file or directory (os error 2)
+error: couldn't read `$DIR/lol`: No such file or directory (os error 2)
   --> $DIR/staged-api-invalid-path-108697.rs:8:1
    |
 LL | mod foo;
diff --git a/tests/ui/use/use.rs b/tests/ui/use/use.rs
index db031500a4a..25b8e529c43 100644
--- a/tests/ui/use/use.rs
+++ b/tests/ui/use/use.rs
@@ -3,7 +3,7 @@
 #![allow(stable_features)]
 
 #![allow(unused_imports)]
-#![feature(start, no_core, core)]
+#![feature(no_core, core)]
 #![no_core]
 
 extern crate std;
@@ -18,5 +18,4 @@ mod baz {
     pub use std::str as x;
 }
 
-#[start]
-pub fn start(_: isize, _: *const *const u8) -> isize { 0 }
+fn main() {}
diff --git a/tests/ui/wf/issue-87495.rs b/tests/ui/wf/issue-87495.rs
index 5aab7431134..ce5c617bbbd 100644
--- a/tests/ui/wf/issue-87495.rs
+++ b/tests/ui/wf/issue-87495.rs
@@ -2,7 +2,7 @@
 
 trait T {
     const CONST: (bool, dyn T);
-    //~^ ERROR: the trait `T` cannot be made into an object [E0038]
+    //~^ ERROR: the trait `T` is not dyn compatible [E0038]
 }
 
 fn main() {}
diff --git a/tests/ui/wf/issue-87495.stderr b/tests/ui/wf/issue-87495.stderr
index 5973fff3e00..7be327e61d1 100644
--- a/tests/ui/wf/issue-87495.stderr
+++ b/tests/ui/wf/issue-87495.stderr
@@ -1,14 +1,15 @@
-error[E0038]: the trait `T` cannot be made into an object
+error[E0038]: the trait `T` is not dyn compatible
   --> $DIR/issue-87495.rs:4:25
    |
 LL |     const CONST: (bool, dyn T);
-   |                         ^^^^^ `T` cannot be made into an object
+   |                         ^^^^^ `T` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/issue-87495.rs:4:11
    |
 LL | trait T {
-   |       - this trait cannot be made into an object...
+   |       - this trait is not dyn compatible...
 LL |     const CONST: (bool, dyn T);
    |           ^^^^^ ...because it contains this associated `const`
    = help: consider moving `CONST` to another trait
diff --git a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr
index 38426545bc8..0b7f4cd4362 100644
--- a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr
+++ b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr
@@ -1,49 +1,52 @@
-error[E0038]: the trait `Trait` cannot be made into an object
+error[E0038]: the trait `Trait` is not dyn compatible
   --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:16:33
    |
 LL |     let t_box: Box<dyn Trait> = Box::new(S);
-   |                                 ^^^^^^^^^^^ `Trait` cannot be made into an object
+   |                                 ^^^^^^^^^^^ `Trait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:6:14
    |
 LL | trait Trait: Sized {}
    |       -----  ^^^^^ ...because it requires `Self: Sized`
    |       |
-   |       this trait cannot be made into an object...
-   = help: only type `S` implements the trait, consider using it directly instead
+   |       this trait is not dyn compatible...
+   = help: only type `S` implements `Trait`; consider using it directly instead.
    = note: required for the cast from `Box<S>` to `Box<dyn Trait>`
 
-error[E0038]: the trait `Trait` cannot be made into an object
+error[E0038]: the trait `Trait` is not dyn compatible
   --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:17:15
    |
 LL |     takes_box(Box::new(S));
-   |               ^^^^^^^^^^^ `Trait` cannot be made into an object
+   |               ^^^^^^^^^^^ `Trait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:6:14
    |
 LL | trait Trait: Sized {}
    |       -----  ^^^^^ ...because it requires `Self: Sized`
    |       |
-   |       this trait cannot be made into an object...
-   = help: only type `S` implements the trait, consider using it directly instead
+   |       this trait is not dyn compatible...
+   = help: only type `S` implements `Trait`; consider using it directly instead.
    = note: required for the cast from `Box<S>` to `Box<(dyn Trait + 'static)>`
 
-error[E0038]: the trait `Trait` cannot be made into an object
+error[E0038]: the trait `Trait` is not dyn compatible
   --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:15:5
    |
 LL |     Box::new(S) as Box<dyn Trait>;
-   |     ^^^^^^^^^^^ `Trait` cannot be made into an object
+   |     ^^^^^^^^^^^ `Trait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:6:14
    |
 LL | trait Trait: Sized {}
    |       -----  ^^^^^ ...because it requires `Self: Sized`
    |       |
-   |       this trait cannot be made into an object...
-   = help: only type `S` implements the trait, consider using it directly instead
+   |       this trait is not dyn compatible...
+   = help: only type `S` implements `Trait`; consider using it directly instead.
    = note: required for the cast from `Box<S>` to `Box<dyn Trait>`
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr
index 94259aa5b0a..3f50e1192cf 100644
--- a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr
+++ b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr
@@ -1,49 +1,52 @@
-error[E0038]: the trait `Trait` cannot be made into an object
+error[E0038]: the trait `Trait` is not dyn compatible
   --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:16:25
    |
 LL |     let t: &dyn Trait = &S;
-   |                         ^^ `Trait` cannot be made into an object
+   |                         ^^ `Trait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:6:14
    |
 LL | trait Trait: Sized {}
    |       -----  ^^^^^ ...because it requires `Self: Sized`
    |       |
-   |       this trait cannot be made into an object...
-   = help: only type `S` implements the trait, consider using it directly instead
+   |       this trait is not dyn compatible...
+   = help: only type `S` implements `Trait`; consider using it directly instead.
    = note: required for the cast from `&S` to `&dyn Trait`
 
-error[E0038]: the trait `Trait` cannot be made into an object
+error[E0038]: the trait `Trait` is not dyn compatible
   --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:17:17
    |
 LL |     takes_trait(&S);
-   |                 ^^ `Trait` cannot be made into an object
+   |                 ^^ `Trait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:6:14
    |
 LL | trait Trait: Sized {}
    |       -----  ^^^^^ ...because it requires `Self: Sized`
    |       |
-   |       this trait cannot be made into an object...
-   = help: only type `S` implements the trait, consider using it directly instead
+   |       this trait is not dyn compatible...
+   = help: only type `S` implements `Trait`; consider using it directly instead.
    = note: required for the cast from `&S` to `&dyn Trait`
 
-error[E0038]: the trait `Trait` cannot be made into an object
+error[E0038]: the trait `Trait` is not dyn compatible
   --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:15:5
    |
 LL |     &S as &dyn Trait;
-   |     ^^ `Trait` cannot be made into an object
+   |     ^^ `Trait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:6:14
    |
 LL | trait Trait: Sized {}
    |       -----  ^^^^^ ...because it requires `Self: Sized`
    |       |
-   |       this trait cannot be made into an object...
-   = help: only type `S` implements the trait, consider using it directly instead
+   |       this trait is not dyn compatible...
+   = help: only type `S` implements `Trait`; consider using it directly instead.
    = note: required for the cast from `&S` to `&dyn Trait`
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr
index 6cd4ebf8412..8f68f9c5b6b 100644
--- a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr
+++ b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr
@@ -12,40 +12,46 @@ LL | |     }
    = note: expected reference `&S`
               found reference `&R`
 
-error[E0038]: the trait `Trait` cannot be made into an object
+error[E0038]: the trait `Trait` is not dyn compatible
   --> $DIR/wf-dyn-incompat-trait-obj-match.rs:26:21
    |
 LL |         Some(()) => &S,
-   |                     ^^ `Trait` cannot be made into an object
+   |                     ^^ `Trait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/wf-dyn-incompat-trait-obj-match.rs:6:14
    |
 LL | trait Trait: Sized {}
    |       -----  ^^^^^ ...because it requires `Self: Sized`
    |       |
-   |       this trait cannot be made into an object...
-   = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Trait` for this new enum and using it instead:
+   |       this trait is not dyn compatible...
+   = help: the following types implement `Trait`:
              S
              R
+           consider defining an enum where each variant holds one of these types,
+           implementing `Trait` for this new enum and using it instead
    = note: required for the cast from `&S` to `&dyn Trait`
 
-error[E0038]: the trait `Trait` cannot be made into an object
+error[E0038]: the trait `Trait` is not dyn compatible
   --> $DIR/wf-dyn-incompat-trait-obj-match.rs:27:17
    |
 LL |         None => &R,
-   |                 ^^ `Trait` cannot be made into an object
+   |                 ^^ `Trait` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/wf-dyn-incompat-trait-obj-match.rs:6:14
    |
 LL | trait Trait: Sized {}
    |       -----  ^^^^^ ...because it requires `Self: Sized`
    |       |
-   |       this trait cannot be made into an object...
-   = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Trait` for this new enum and using it instead:
+   |       this trait is not dyn compatible...
+   = help: the following types implement `Trait`:
              S
              R
+           consider defining an enum where each variant holds one of these types,
+           implementing `Trait` for this new enum and using it instead
    = note: required for the cast from `&R` to `&dyn Trait`
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/wf/wf-dyn-incompatible.stderr b/tests/ui/wf/wf-dyn-incompatible.stderr
index cf016b63c74..1803376aaa1 100644
--- a/tests/ui/wf/wf-dyn-incompatible.stderr
+++ b/tests/ui/wf/wf-dyn-incompatible.stderr
@@ -1,14 +1,15 @@
-error[E0038]: the trait `A` cannot be made into an object
+error[E0038]: the trait `A` is not dyn compatible
   --> $DIR/wf-dyn-incompatible.rs:9:13
    |
 LL |     let _x: &dyn A;
-   |             ^^^^^^ `A` cannot be made into an object
+   |             ^^^^^^ `A` is not dyn compatible
    |
-note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/wf-dyn-incompatible.rs:5:23
    |
 LL | trait A {
-   |       - this trait cannot be made into an object...
+   |       - this trait is not dyn compatible...
 LL |     fn foo(&self, _x: &Self);
    |                       ^^^^^ ...because method `foo` references the `Self` type in this parameter
    = help: consider moving `foo` to another trait
diff --git a/tests/ui/wf/wf-fn-where-clause.stderr b/tests/ui/wf/wf-fn-where-clause.stderr
index 76671dedabf..d73376e9861 100644
--- a/tests/ui/wf/wf-fn-where-clause.stderr
+++ b/tests/ui/wf/wf-fn-where-clause.stderr
@@ -14,14 +14,15 @@ help: consider further restricting type parameter `U` with trait `Copy`
 LL | fn foo<T,U>() where T: ExtraCopy<U>, U: std::marker::Copy
    |                                    ++++++++++++++++++++++
 
-error[E0038]: the trait `Copy` cannot be made into an object
+error[E0038]: the trait `Copy` is not dyn compatible
   --> $DIR/wf-fn-where-clause.rs:12:16
    |
 LL | fn bar() where Vec<dyn Copy>:, {}
-   |                ^^^^^^^^^^^^^ `Copy` cannot be made into an object
+   |                ^^^^^^^^^^^^^ `Copy` is not dyn compatible
    |
-   = note: the trait cannot be made into an object because it requires `Self: Sized`
-   = note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+   = note: the trait is not dyn compatible because it requires `Self: Sized`
+   = note: for a trait to be dyn compatible it needs to allow building a vtable
+           for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
 
 error[E0277]: the size for values of type `(dyn Copy + 'static)` cannot be known at compilation time
   --> $DIR/wf-fn-where-clause.rs:12:16
diff --git a/tests/ui/wf/wf-trait-fn-arg.stderr b/tests/ui/wf/wf-trait-fn-arg.current.stderr
index 8b35f36fa68..d5dd36fad6d 100644
--- a/tests/ui/wf/wf-trait-fn-arg.stderr
+++ b/tests/ui/wf/wf-trait-fn-arg.current.stderr
@@ -1,14 +1,14 @@
 error[E0277]: the trait bound `Self: Eq` is not satisfied
-  --> $DIR/wf-trait-fn-arg.rs:10:23
+  --> $DIR/wf-trait-fn-arg.rs:16:23
    |
 LL |     fn bar(&self, x: &Bar<Self>);
    |                       ^^^^^^^^^ the trait `Eq` is not implemented for `Self`
    |
 note: required by a bound in `Bar`
-  --> $DIR/wf-trait-fn-arg.rs:7:14
+  --> $DIR/wf-trait-fn-arg.rs:11:15
    |
-LL | struct Bar<T:Eq+?Sized> { value: Box<T> }
-   |              ^^ required by this bound in `Bar`
+LL | struct Bar<T: Eq + ?Sized> {
+   |               ^^ required by this bound in `Bar`
 help: consider further restricting `Self`
    |
 LL |     fn bar(&self, x: &Bar<Self>) where Self: Eq;
diff --git a/tests/ui/wf/wf-trait-fn-arg.next.stderr b/tests/ui/wf/wf-trait-fn-arg.next.stderr
new file mode 100644
index 00000000000..c55dc5c8a12
--- /dev/null
+++ b/tests/ui/wf/wf-trait-fn-arg.next.stderr
@@ -0,0 +1,14 @@
+error[E0277]: the trait bound `Self: Eq` is not satisfied
+  --> $DIR/wf-trait-fn-arg.rs:16:23
+   |
+LL |     fn bar(&self, x: &Bar<Self>);
+   |                       ^^^^^^^^^ the trait `Eq` is not implemented for `Self`
+   |
+help: consider further restricting `Self`
+   |
+LL |     fn bar(&self, x: &Bar<Self>) where Self: Eq;
+   |                                  ++++++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/wf/wf-trait-fn-arg.rs b/tests/ui/wf/wf-trait-fn-arg.rs
index 0445699427e..13a5b32828d 100644
--- a/tests/ui/wf/wf-trait-fn-arg.rs
+++ b/tests/ui/wf/wf-trait-fn-arg.rs
@@ -1,16 +1,22 @@
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+
 // Check that we test WF conditions for fn arguments in a trait definition.
 
 #![feature(rustc_attrs)]
 #![allow(dead_code)]
 #![allow(unused_variables)]
 
-struct Bar<T:Eq+?Sized> { value: Box<T> }
+struct Bar<T: Eq + ?Sized> {
+    value: Box<T>,
+}
 
 trait Foo {
     fn bar(&self, x: &Bar<Self>);
-        //~^ ERROR E0277
-        //
-        // Here, Eq ought to be implemented.
+    //~^ ERROR E0277
+    //
+    // Here, Eq ought to be implemented.
 }
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/wf/wf-trait-fn-ret.stderr b/tests/ui/wf/wf-trait-fn-ret.current.stderr
index 3d70f04def2..0ad786c2fd5 100644
--- a/tests/ui/wf/wf-trait-fn-ret.stderr
+++ b/tests/ui/wf/wf-trait-fn-ret.current.stderr
@@ -1,14 +1,14 @@
 error[E0277]: the trait bound `Self: Eq` is not satisfied
-  --> $DIR/wf-trait-fn-ret.rs:10:23
+  --> $DIR/wf-trait-fn-ret.rs:15:23
    |
 LL |     fn bar(&self) -> &Bar<Self>;
    |                       ^^^^^^^^^ the trait `Eq` is not implemented for `Self`
    |
 note: required by a bound in `Bar`
-  --> $DIR/wf-trait-fn-ret.rs:7:14
+  --> $DIR/wf-trait-fn-ret.rs:10:15
    |
-LL | struct Bar<T:Eq+?Sized> { value: Box<T> }
-   |              ^^ required by this bound in `Bar`
+LL | struct Bar<T: Eq + ?Sized> {
+   |               ^^ required by this bound in `Bar`
 help: consider further restricting `Self`
    |
 LL |     fn bar(&self) -> &Bar<Self> where Self: Eq;
diff --git a/tests/ui/wf/wf-trait-fn-ret.next.stderr b/tests/ui/wf/wf-trait-fn-ret.next.stderr
new file mode 100644
index 00000000000..b3dca17672d
--- /dev/null
+++ b/tests/ui/wf/wf-trait-fn-ret.next.stderr
@@ -0,0 +1,14 @@
+error[E0277]: the trait bound `Self: Eq` is not satisfied
+  --> $DIR/wf-trait-fn-ret.rs:15:23
+   |
+LL |     fn bar(&self) -> &Bar<Self>;
+   |                       ^^^^^^^^^ the trait `Eq` is not implemented for `Self`
+   |
+help: consider further restricting `Self`
+   |
+LL |     fn bar(&self) -> &Bar<Self> where Self: Eq;
+   |                                 ++++++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/wf/wf-trait-fn-ret.rs b/tests/ui/wf/wf-trait-fn-ret.rs
index f49e4308770..c00f6dd10af 100644
--- a/tests/ui/wf/wf-trait-fn-ret.rs
+++ b/tests/ui/wf/wf-trait-fn-ret.rs
@@ -1,16 +1,21 @@
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
 // Check that we test WF conditions for fn return types in a trait definition.
 
 #![feature(rustc_attrs)]
 #![allow(dead_code)]
 #![allow(unused_variables)]
 
-struct Bar<T:Eq+?Sized> { value: Box<T> }
+struct Bar<T: Eq + ?Sized> {
+    value: Box<T>,
+}
 
 trait Foo {
     fn bar(&self) -> &Bar<Self>;
-        //~^ ERROR E0277
-        //
-        // Here, Eq ought to be implemented.
+    //~^ ERROR E0277
+    //
+    // Here, Eq ought to be implemented.
 }
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/wf/wf-trait-fn-where-clause.current.stderr b/tests/ui/wf/wf-trait-fn-where-clause.current.stderr
new file mode 100644
index 00000000000..db5454d0f3c
--- /dev/null
+++ b/tests/ui/wf/wf-trait-fn-where-clause.current.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `Self: Eq` is not satisfied
+  --> $DIR/wf-trait-fn-where-clause.rs:18:20
+   |
+LL |         Bar<Self>: Copy;
+   |                    ^^^^ the trait `Eq` is not implemented for `Self`
+   |
+note: required by a bound in `Bar`
+  --> $DIR/wf-trait-fn-where-clause.rs:10:15
+   |
+LL | struct Bar<T: Eq + ?Sized> {
+   |               ^^ required by this bound in `Bar`
+help: consider further restricting `Self`
+   |
+LL |         Bar<Self>: Copy, Self: Eq;
+   |                        ++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/wf/wf-trait-fn-where-clause.next.stderr b/tests/ui/wf/wf-trait-fn-where-clause.next.stderr
new file mode 100644
index 00000000000..8c8a5fa3e70
--- /dev/null
+++ b/tests/ui/wf/wf-trait-fn-where-clause.next.stderr
@@ -0,0 +1,14 @@
+error[E0277]: the trait bound `Self: Eq` is not satisfied
+  --> $DIR/wf-trait-fn-where-clause.rs:18:20
+   |
+LL |         Bar<Self>: Copy;
+   |                    ^^^^ the trait `Eq` is not implemented for `Self`
+   |
+help: consider further restricting `Self`
+   |
+LL |         Bar<Self>: Copy, Self: Eq;
+   |                        ++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/wf/wf-trait-fn-where-clause.rs b/tests/ui/wf/wf-trait-fn-where-clause.rs
index 1d2427ff981..9e36682e449 100644
--- a/tests/ui/wf/wf-trait-fn-where-clause.rs
+++ b/tests/ui/wf/wf-trait-fn-where-clause.rs
@@ -1,17 +1,24 @@
-// Check that we test WF conditions for fn where clauses in a trait definition.
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
 
+// Check that we test WF conditions for fn where clauses in a trait definition.
 
 #![allow(dead_code)]
 #![allow(unused_variables)]
 
-struct Bar<T:Eq+?Sized> { value: Box<T> }
+struct Bar<T: Eq + ?Sized> {
+    value: Box<T>,
+}
 
 trait Foo {
-    fn bar(&self) where Self: Sized, Bar<Self>: Copy;
-        //~^ ERROR E0277
-        //
-        // Here, Eq ought to be implemented.
+    fn bar(&self)
+    where
+        Self: Sized,
+        Bar<Self>: Copy;
+    //~^ ERROR E0277
+    //
+    // Here, Eq ought to be implemented.
 }
 
-
-fn main() { }
+fn main() {}
diff --git a/tests/ui/wf/wf-trait-fn-where-clause.stderr b/tests/ui/wf/wf-trait-fn-where-clause.stderr
deleted file mode 100644
index 0ad3b58e7c7..00000000000
--- a/tests/ui/wf/wf-trait-fn-where-clause.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0277]: the trait bound `Self: Eq` is not satisfied
-  --> $DIR/wf-trait-fn-where-clause.rs:10:49
-   |
-LL |     fn bar(&self) where Self: Sized, Bar<Self>: Copy;
-   |                                                 ^^^^ the trait `Eq` is not implemented for `Self`
-   |
-note: required by a bound in `Bar`
-  --> $DIR/wf-trait-fn-where-clause.rs:7:14
-   |
-LL | struct Bar<T:Eq+?Sized> { value: Box<T> }
-   |              ^^ required by this bound in `Bar`
-help: consider further restricting `Self`
-   |
-LL |     fn bar(&self) where Self: Sized, Bar<Self>: Copy, Self: Eq;
-   |                                                     ++++++++++
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/where-clauses/where-clauses-method-unsatisfied.stderr b/tests/ui/where-clauses/where-clauses-method-unsatisfied.current.stderr
index 840df342ef9..d1de813a2d9 100644
--- a/tests/ui/where-clauses/where-clauses-method-unsatisfied.stderr
+++ b/tests/ui/where-clauses/where-clauses-method-unsatisfied.current.stderr
@@ -1,14 +1,17 @@
 error[E0277]: the trait bound `Bar: Eq` is not satisfied
-  --> $DIR/where-clauses-method-unsatisfied.rs:18:7
+  --> $DIR/where-clauses-method-unsatisfied.rs:24:7
    |
 LL |     x.equals(&x);
    |       ^^^^^^ the trait `Eq` is not implemented for `Bar`
    |
 note: required by a bound in `Foo::<T>::equals`
-  --> $DIR/where-clauses-method-unsatisfied.rs:11:52
+  --> $DIR/where-clauses-method-unsatisfied.rs:16:12
    |
-LL |     fn equals(&self, u: &Foo<T>) -> bool where T : Eq {
-   |                                                    ^^ required by this bound in `Foo::<T>::equals`
+LL |     fn equals(&self, u: &Foo<T>) -> bool
+   |        ------ required by a bound in this associated function
+LL |     where
+LL |         T: Eq,
+   |            ^^ required by this bound in `Foo::<T>::equals`
 help: consider annotating `Bar` with `#[derive(Eq)]`
    |
 LL + #[derive(Eq)]
diff --git a/tests/ui/where-clauses/where-clauses-method-unsatisfied.next.stderr b/tests/ui/where-clauses/where-clauses-method-unsatisfied.next.stderr
new file mode 100644
index 00000000000..d1de813a2d9
--- /dev/null
+++ b/tests/ui/where-clauses/where-clauses-method-unsatisfied.next.stderr
@@ -0,0 +1,23 @@
+error[E0277]: the trait bound `Bar: Eq` is not satisfied
+  --> $DIR/where-clauses-method-unsatisfied.rs:24:7
+   |
+LL |     x.equals(&x);
+   |       ^^^^^^ the trait `Eq` is not implemented for `Bar`
+   |
+note: required by a bound in `Foo::<T>::equals`
+  --> $DIR/where-clauses-method-unsatisfied.rs:16:12
+   |
+LL |     fn equals(&self, u: &Foo<T>) -> bool
+   |        ------ required by a bound in this associated function
+LL |     where
+LL |         T: Eq,
+   |            ^^ required by this bound in `Foo::<T>::equals`
+help: consider annotating `Bar` with `#[derive(Eq)]`
+   |
+LL + #[derive(Eq)]
+LL | struct Bar; // does not implement Eq
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/where-clauses/where-clauses-method-unsatisfied.rs b/tests/ui/where-clauses/where-clauses-method-unsatisfied.rs
index a8ae0296407..34e9d9b57d1 100644
--- a/tests/ui/where-clauses/where-clauses-method-unsatisfied.rs
+++ b/tests/ui/where-clauses/where-clauses-method-unsatisfied.rs
@@ -1,14 +1,20 @@
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
 // Test that a where clause attached to a method allows us to add
 // additional constraints to a parameter out of scope.
 
 struct Foo<T> {
-    value: T
+    value: T,
 }
 
 struct Bar; // does not implement Eq
 
 impl<T> Foo<T> {
-    fn equals(&self, u: &Foo<T>) -> bool where T : Eq {
+    fn equals(&self, u: &Foo<T>) -> bool
+    where
+        T: Eq,
+    {
         self.value == u.value
     }
 }
diff --git a/tests/ui/where-clauses/where-clauses-unsatisfied.stderr b/tests/ui/where-clauses/where-clauses-unsatisfied.current.stderr
index 205b82d49bf..485b9459ddd 100644
--- a/tests/ui/where-clauses/where-clauses-unsatisfied.stderr
+++ b/tests/ui/where-clauses/where-clauses-unsatisfied.current.stderr
@@ -1,14 +1,17 @@
 error[E0277]: the trait bound `Struct: Eq` is not satisfied
-  --> $DIR/where-clauses-unsatisfied.rs:6:10
+  --> $DIR/where-clauses-unsatisfied.rs:15:10
    |
 LL |     drop(equal(&Struct, &Struct))
    |          ^^^^^ the trait `Eq` is not implemented for `Struct`
    |
 note: required by a bound in `equal`
-  --> $DIR/where-clauses-unsatisfied.rs:1:45
+  --> $DIR/where-clauses-unsatisfied.rs:7:8
    |
-LL | fn equal<T>(a: &T, b: &T) -> bool where T : Eq { a == b }
-   |                                             ^^ required by this bound in `equal`
+LL | fn equal<T>(a: &T, b: &T) -> bool
+   |    ----- required by a bound in this function
+LL | where
+LL |     T: Eq,
+   |        ^^ required by this bound in `equal`
 help: consider annotating `Struct` with `#[derive(Eq)]`
    |
 LL + #[derive(Eq)]
diff --git a/tests/ui/where-clauses/where-clauses-unsatisfied.next.stderr b/tests/ui/where-clauses/where-clauses-unsatisfied.next.stderr
new file mode 100644
index 00000000000..485b9459ddd
--- /dev/null
+++ b/tests/ui/where-clauses/where-clauses-unsatisfied.next.stderr
@@ -0,0 +1,23 @@
+error[E0277]: the trait bound `Struct: Eq` is not satisfied
+  --> $DIR/where-clauses-unsatisfied.rs:15:10
+   |
+LL |     drop(equal(&Struct, &Struct))
+   |          ^^^^^ the trait `Eq` is not implemented for `Struct`
+   |
+note: required by a bound in `equal`
+  --> $DIR/where-clauses-unsatisfied.rs:7:8
+   |
+LL | fn equal<T>(a: &T, b: &T) -> bool
+   |    ----- required by a bound in this function
+LL | where
+LL |     T: Eq,
+   |        ^^ required by this bound in `equal`
+help: consider annotating `Struct` with `#[derive(Eq)]`
+   |
+LL + #[derive(Eq)]
+LL | struct Struct;
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/where-clauses/where-clauses-unsatisfied.rs b/tests/ui/where-clauses/where-clauses-unsatisfied.rs
index 8b067d30a2a..48798e2a15d 100644
--- a/tests/ui/where-clauses/where-clauses-unsatisfied.rs
+++ b/tests/ui/where-clauses/where-clauses-unsatisfied.rs
@@ -1,4 +1,13 @@
-fn equal<T>(a: &T, b: &T) -> bool where T : Eq { a == b }
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+
+fn equal<T>(a: &T, b: &T) -> bool
+where
+    T: Eq,
+{
+    a == b
+}
 
 struct Struct;
 
diff --git a/triagebot.toml b/triagebot.toml
index 5ee52bbf435..4a09fe116a5 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -1025,6 +1025,7 @@ users_on_vacation = [
     "nnethercote",
     "spastorino",
     "workingjubilee",
+    "kobzol"
 ]
 
 [[assign.warn_non_default_branch.exceptions]]