about summary refs log tree commit diff
path: root/src/tools
diff options
context:
space:
mode:
authorAmanieu d'Antras <amanieu@gmail.com>2025-07-08 15:10:51 +0000
committerGitHub <noreply@github.com>2025-07-08 15:10:51 +0000
commita310bdd0d87163341f9344eff80860cc8519f943 (patch)
tree05a5849ce18ed88207f14d23da57a06dfc1e8126 /src/tools
parent061a941adc570ed717dfa2f3508a9038b8300eca (diff)
parentbdead41b65ed10d6c947b20ddb724f1ae59e2b48 (diff)
Merge pull request #1853 from Kobzol/pull-fixed
Perform the first rustc pull.. for the second time
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/build-manifest/src/main.rs4
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/approx_const.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/utils.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/default_union_representation.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_clike.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/exhaustive_items.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/large_include_file.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_strip.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/open_options.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/types/type_complexity.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils/mod.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/attrs.rs9
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs10
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs14
-rw-r--r--src/tools/clippy/clippy_utils/src/diagnostics.rs7
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs14
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs4
-rw-r--r--src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr2
-rw-r--r--src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr2
-rw-r--r--src/tools/clippy/tests/ui/track-diagnostics-clippy.rs22
-rw-r--r--src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr29
-rw-r--r--src/tools/clippy/tests/ui/track-diagnostics.rs1
-rw-r--r--src/tools/clippy/tests/ui/track-diagnostics.stderr3
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_safety_comment.stderr4
-rw-r--r--src/tools/compiletest/Cargo.toml4
-rw-r--r--src/tools/compiletest/src/bin/main.rs24
-rw-r--r--src/tools/compiletest/src/common.rs404
-rw-r--r--src/tools/compiletest/src/debuggers.rs2
-rw-r--r--src/tools/compiletest/src/diagnostics.rs46
-rw-r--r--src/tools/compiletest/src/directive-list.rs2
-rw-r--r--src/tools/compiletest/src/directives.rs (renamed from src/tools/compiletest/src/header.rs)65
-rw-r--r--src/tools/compiletest/src/directives/auxiliary.rs (renamed from src/tools/compiletest/src/header/auxiliary.rs)2
-rw-r--r--src/tools/compiletest/src/directives/cfg.rs (renamed from src/tools/compiletest/src/header/cfg.rs)2
-rw-r--r--src/tools/compiletest/src/directives/needs.rs (renamed from src/tools/compiletest/src/header/needs.rs)2
-rw-r--r--src/tools/compiletest/src/directives/test-auxillary/error_annotation.rs (renamed from src/tools/compiletest/src/header/test-auxillary/error_annotation.rs)0
-rw-r--r--src/tools/compiletest/src/directives/test-auxillary/known_directive.rs (renamed from src/tools/compiletest/src/header/test-auxillary/known_directive.rs)0
-rw-r--r--src/tools/compiletest/src/directives/test-auxillary/not_rs.Makefile (renamed from src/tools/compiletest/src/header/test-auxillary/not_rs.Makefile)0
-rw-r--r--src/tools/compiletest/src/directives/test-auxillary/unknown_directive.rs (renamed from src/tools/compiletest/src/header/test-auxillary/unknown_directive.rs)0
-rw-r--r--src/tools/compiletest/src/directives/tests.rs (renamed from src/tools/compiletest/src/header/tests.rs)8
-rw-r--r--src/tools/compiletest/src/executor.rs12
-rw-r--r--src/tools/compiletest/src/lib.rs56
-rw-r--r--src/tools/compiletest/src/main.rs36
-rw-r--r--src/tools/compiletest/src/runtest.rs47
-rw-r--r--src/tools/compiletest/src/runtest/codegen_units.rs4
-rw-r--r--src/tools/compiletest/src/runtest/debuginfo.rs10
-rw-r--r--src/tools/compiletest/src/runtest/ui.rs4
-rw-r--r--src/tools/miri/.github/workflows/ci.yml79
-rw-r--r--src/tools/miri/.github/workflows/setup/action.yml12
-rw-r--r--src/tools/miri/CONTRIBUTING.md9
-rw-r--r--src/tools/miri/Cargo.lock200
-rw-r--r--src/tools/miri/Cargo.toml9
-rw-r--r--src/tools/miri/README.md9
-rw-r--r--src/tools/miri/cargo-miri/src/phases.rs5
-rwxr-xr-xsrc/tools/miri/ci/ci.sh43
-rw-r--r--src/tools/miri/etc/rust_analyzer_helix.toml12
-rwxr-xr-xsrc/tools/miri/miri28
-rw-r--r--src/tools/miri/miri-script/src/commands.rs104
-rw-r--r--src/tools/miri/miri-script/src/coverage.rs7
-rw-r--r--src/tools/miri/miri-script/src/main.rs38
-rw-r--r--src/tools/miri/miri-script/src/util.rs90
-rw-r--r--src/tools/miri/miri.bat4
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/rustfmt.toml5
-rw-r--r--src/tools/miri/src/alloc/isolated_alloc.rs177
-rw-r--r--src/tools/miri/src/alloc_addresses/mod.rs19
-rw-r--r--src/tools/miri/src/alloc_addresses/reuse_pool.rs2
-rw-r--r--src/tools/miri/src/bin/log/mod.rs2
-rw-r--r--src/tools/miri/src/bin/log/setup.rs126
-rw-r--r--src/tools/miri/src/bin/log/tracing_chrome.rs625
-rw-r--r--src/tools/miri/src/bin/miri.rs179
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs6
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs2
-rw-r--r--src/tools/miri/src/concurrency/data_race.rs8
-rw-r--r--src/tools/miri/src/concurrency/init_once.rs98
-rw-r--r--src/tools/miri/src/concurrency/mod.rs26
-rw-r--r--src/tools/miri/src/concurrency/sync.rs136
-rw-r--r--src/tools/miri/src/concurrency/thread.rs188
-rw-r--r--src/tools/miri/src/diagnostics.rs60
-rw-r--r--src/tools/miri/src/eval.rs17
-rw-r--r--src/tools/miri/src/helpers.rs11
-rw-r--r--src/tools/miri/src/intrinsics/mod.rs106
-rw-r--r--src/tools/miri/src/intrinsics/simd.rs2
-rw-r--r--src/tools/miri/src/lib.rs17
-rw-r--r--src/tools/miri/src/machine.rs21
-rw-r--r--src/tools/miri/src/provenance_gc.rs6
-rw-r--r--src/tools/miri/src/shims/backtrace.rs2
-rw-r--r--src/tools/miri/src/shims/env.rs31
-rw-r--r--src/tools/miri/src/shims/extern_static.rs13
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs10
-rw-r--r--src/tools/miri/src/shims/mod.rs2
-rw-r--r--src/tools/miri/src/shims/native_lib/mod.rs (renamed from src/tools/miri/src/shims/native_lib.rs)212
-rw-r--r--src/tools/miri/src/shims/native_lib/trace/child.rs251
-rw-r--r--src/tools/miri/src/shims/native_lib/trace/messages.rs80
-rw-r--r--src/tools/miri/src/shims/native_lib/trace/mod.rs8
-rw-r--r--src/tools/miri/src/shims/native_lib/trace/parent.rs660
-rw-r--r--src/tools/miri/src/shims/panic.rs14
-rw-r--r--src/tools/miri/src/shims/time.rs68
-rw-r--r--src/tools/miri/src/shims/tls.rs6
-rw-r--r--src/tools/miri/src/shims/unix/env.rs75
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs18
-rw-r--r--src/tools/miri/src/shims/unix/freebsd/foreign_items.rs5
-rw-r--r--src/tools/miri/src/shims/unix/linux/foreign_items.rs4
-rw-r--r--src/tools/miri/src/shims/unix/linux/mem.rs3
-rw-r--r--src/tools/miri/src/shims/unix/linux_like/sync.rs7
-rw-r--r--src/tools/miri/src/shims/unix/linux_like/syscall.rs6
-rw-r--r--src/tools/miri/src/shims/unix/macos/foreign_items.rs5
-rw-r--r--src/tools/miri/src/shims/unix/macos/sync.rs5
-rw-r--r--src/tools/miri/src/shims/unix/mem.rs5
-rw-r--r--src/tools/miri/src/shims/unix/sync.rs43
-rw-r--r--src/tools/miri/src/shims/unix/thread.rs14
-rw-r--r--src/tools/miri/src/shims/windows/foreign_items.rs20
-rw-r--r--src/tools/miri/src/shims/windows/handle.rs4
-rw-r--r--src/tools/miri/src/shims/windows/sync.rs37
-rw-r--r--src/tools/miri/src/shims/windows/thread.rs13
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/windows_thread_invalid.rs9
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/windows_thread_invalid.stderr13
-rw-r--r--src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr6
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs7
-rw-r--r--src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr28
-rw-r--r--src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs8
-rw-r--r--src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr28
-rw-r--r--src/tools/miri/tests/fail/validity/uninit_float.stderr2
-rw-r--r--src/tools/miri/tests/fail/validity/uninit_integer.stderr2
-rw-r--r--src/tools/miri/tests/fail/validity/uninit_raw_ptr.stderr2
-rw-r--r--src/tools/miri/tests/native-lib/pass/ptr_read_access.rs4
-rw-r--r--src/tools/miri/tests/native-lib/pass/ptr_write_access.rs3
-rw-r--r--src/tools/miri/tests/native-lib/pass/scalar_arguments.rs4
-rw-r--r--src/tools/miri/tests/native-lib/scalar_arguments.c4
-rw-r--r--src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs5
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-time.rs114
-rw-r--r--src/tools/miri/tests/pass-dep/shims/gettid.rs183
-rw-r--r--src/tools/miri/tests/pass/alloc-access-tracking.rs4
-rw-r--r--src/tools/miri/tests/pass/dyn-star.rs103
-rw-r--r--src/tools/miri/tests/pass/float.rs27
-rw-r--r--src/tools/miri/tests/pass/float_nan.rs26
-rw-r--r--src/tools/miri/tests/pass/intrinsics/portable-simd.rs8
-rw-r--r--src/tools/miri/tests/pass/shims/time.rs10
-rw-r--r--src/tools/miri/tests/ui.rs30
-rw-r--r--src/tools/opt-dist/src/exec.rs22
-rw-r--r--src/tools/opt-dist/src/main.rs5
-rw-r--r--src/tools/opt-dist/src/tests.rs2
-rw-r--r--src/tools/run-make-support/Cargo.toml10
-rw-r--r--src/tools/rust-analyzer/.github/workflows/ci.yaml39
-rw-r--r--src/tools/rust-analyzer/.github/workflows/release.yaml4
-rw-r--r--src/tools/rust-analyzer/Cargo.lock60
-rw-r--r--src/tools/rust-analyzer/Cargo.toml8
-rw-r--r--src/tools/rust-analyzer/crates/base-db/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/input.rs45
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/lib.rs11
-rw-r--r--src/tools/rust-analyzer/crates/cfg/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/db.rs21
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs76
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs35
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/path.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/import_map.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs24
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs63
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs80
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/signatures.rs90
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/visibility.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs25
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs140
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs61
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/db.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/files.rs20
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/lib.rs28
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/name.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/prettify_macro_expansion_.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/db.rs40
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs90
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/generics.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs50
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs22
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs55
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs88
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs21
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs28
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs43
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs28
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs76
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/utils.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/variance.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/attrs.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/diagnostics.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/display.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs80
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs43
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/symbols.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs22
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs21
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs26
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs63
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs163
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs86
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/utils.rs15
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs34
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs27
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs31
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/search.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/ide/Cargo.toml1
-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.rs27
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/file_structure.rs50
-rwxr-xr-xsrc/tools/rust-analyzer/crates/ide/src/folding_ranges.rs94
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_definition.rs315
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/highlight_related.rs352
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs31
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs108
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/navigation_target.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/references.rs223
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/runnables.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs2
-rw-r--r--src/tools/rust-analyzer/crates/intern/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs2
-rw-r--r--src/tools/rust-analyzer/crates/load-cargo/src/lib.rs95
-rw-r--r--src/tools/rust-analyzer/crates/mbe/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/parser/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs7
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/lexed_str.rs131
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_param_bounds.rast3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_param_bounds.rs2
-rw-r--r--src/tools/rust-analyzer/crates/paths/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/build.rs12
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/profile/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/project-model/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs100
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs8
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/env.rs22
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/sysroot.rs29
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/tests.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs129
-rw-r--r--src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs8
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs9
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs7
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs5
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs19
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs6
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs5
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs11
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs39
-rw-r--r--src/tools/rust-analyzer/crates/span/src/ast_id.rs15
-rw-r--r--src/tools/rust-analyzer/crates/span/src/hygiene.rs16
-rw-r--r--src/tools/rust-analyzer/crates/stdx/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/syntax-bridge/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/syntax/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/syntax/rust.ungram2
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs4
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/make.rs7
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs41
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs94
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs2
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/validation.rs28
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/fixture.rs22
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/minicore.rs188
-rw-r--r--src/tools/rust-analyzer/crates/toolchain/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/tt/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/tt/src/iter.rs1
-rw-r--r--src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/vfs/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/vfs/src/file_set.rs6
-rw-r--r--src/tools/rust-analyzer/docs/book/src/SUMMARY.md1
-rw-r--r--src/tools/rust-analyzer/docs/book/src/configuration_generated.md7
-rw-r--r--src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md18
-rw-r--r--src/tools/rust-analyzer/docs/book/src/faq.md7
-rw-r--r--src/tools/rust-analyzer/docs/book/src/non_cargo_based_projects.md3
-rw-r--r--src/tools/rust-analyzer/docs/book/src/troubleshooting.md3
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json10
-rw-r--r--src/tools/rust-analyzer/editors/code/src/client.ts114
-rw-r--r--src/tools/rust-analyzer/editors/code/src/commands.ts4
-rw-r--r--src/tools/rust-analyzer/editors/code/src/main.ts2
-rw-r--r--src/tools/rust-analyzer/editors/code/src/run.ts57
-rw-r--r--src/tools/rust-analyzer/rust-version2
-rw-r--r--src/tools/rust-installer/README.md2
-rw-r--r--src/tools/rustbook/Cargo.lock160
-rw-r--r--src/tools/rustdoc-gui-test/src/main.rs2
-rw-r--r--src/tools/rustdoc-gui/tester.js2
-rw-r--r--src/tools/rustfmt/src/spanned.rs2
-rw-r--r--src/tools/rustfmt/src/types.rs28
-rw-r--r--src/tools/rustfmt/tests/source/let_chains.rs2
-rw-r--r--src/tools/rustfmt/tests/target/issue_5542.rs10
-rw-r--r--src/tools/rustfmt/tests/target/let_chains.rs2
-rw-r--r--src/tools/test-float-parse/src/lib.rs1
-rw-r--r--src/tools/test-float-parse/src/traits.rs1
-rw-r--r--src/tools/test-float-parse/src/ui.rs2
-rw-r--r--src/tools/tidy/src/ext_tool_checks.rs59
-rw-r--r--src/tools/tidy/src/issues.txt7
-rw-r--r--src/tools/tidy/src/rustdoc_js.rs3
391 files changed, 8107 insertions, 2994 deletions
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 4c53ea42793..0520eff0fa2 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -14,6 +14,7 @@ use crate::versions::{PkgType, Versions};
 
 static HOSTS: &[&str] = &[
     "aarch64-apple-darwin",
+    "aarch64-pc-windows-gnullvm",
     "aarch64-pc-windows-msvc",
     "aarch64-unknown-linux-gnu",
     "aarch64-unknown-linux-musl",
@@ -44,6 +45,7 @@ static HOSTS: &[&str] = &[
     "x86_64-apple-darwin",
     "x86_64-pc-solaris",
     "x86_64-pc-windows-gnu",
+    "x86_64-pc-windows-gnullvm",
     "x86_64-pc-windows-msvc",
     "x86_64-unknown-freebsd",
     "x86_64-unknown-illumos",
@@ -470,7 +472,7 @@ impl Builder {
                 }
                 // so is rust-mingw if it's available for the target
                 PkgType::RustMingw => {
-                    if host.contains("pc-windows-gnu") {
+                    if host.ends_with("pc-windows-gnu") {
                         components.push(host_component(pkg));
                     }
                 }
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 409fed7dc1553d49cb9a8c0637d12d65571346c
+Subproject 930b4f62cfcd1f0eabdb30a56d91bf6844b739b
diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs
index 852e48cbcae..5ed4c82634a 100644
--- a/src/tools/clippy/clippy_lints/src/approx_const.rs
+++ b/src/tools/clippy/clippy_lints/src/approx_const.rs
@@ -74,7 +74,7 @@ impl ApproxConstant {
 }
 
 impl LateLintPass<'_> for ApproxConstant {
-    fn check_lit(&mut self, cx: &LateContext<'_>, _hir_id: HirId, lit: &Lit, _negated: bool) {
+    fn check_lit(&mut self, cx: &LateContext<'_>, _hir_id: HirId, lit: Lit, _negated: bool) {
         match lit.node {
             LitKind::Float(s, LitFloatType::Suffixed(fty)) => match fty {
                 FloatTy::F16 => self.check_known_consts(cx, lit.span, s, "f16"),
diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
index b9ae9afe851..8b6bfaebbe5 100644
--- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
+++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
@@ -266,7 +266,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
             .tcx
             .hir_attrs(item.hir_id())
             .iter()
-            .any(|attr| matches!(attr, Attribute::Parsed(AttributeKind::Repr(..))))
+            .any(|attr| matches!(attr, Attribute::Parsed(AttributeKind::Repr{ .. })))
         {
             // Do not lint items with a `#[repr]` attribute as their layout may be imposed by an external API.
             return;
diff --git a/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs
index 05d8a8c26d1..3e8808cec61 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs
@@ -9,7 +9,7 @@ use clippy_utils::msrvs::{self, Msrv};
 use super::REPR_PACKED_WITHOUT_ABI;
 
 pub(super) fn check(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute], msrv: Msrv) {
-    if let Some(reprs) = find_attr!(attrs, AttributeKind::Repr(r) => r) {
+    if let Some(reprs) = find_attr!(attrs, AttributeKind::Repr { reprs, .. } => reprs) {
         let packed_span = reprs
             .iter()
             .find(|(r, _)| matches!(r, ReprAttr::ReprPacked(..)))
diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
index 8f95e44bf85..581fe33ea0b 100644
--- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
@@ -42,7 +42,7 @@ fn extract_bool_lit(e: &Expr<'_>) -> Option<bool> {
     }) = e.kind
         && !e.span.from_expansion()
     {
-        Some(*b)
+        Some(b)
     } else {
         None
     }
diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs
index 105477093b5..55e27a05f3c 100644
--- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs
@@ -17,7 +17,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
         ty::FnDef(..) | ty::FnPtr(..) => {
             let mut applicability = Applicability::MaybeIncorrect;
 
-            if to_nbits >= cx.tcx.data_layout.pointer_size.bits() && !cast_to.is_usize() {
+            if to_nbits >= cx.tcx.data_layout.pointer_size().bits() && !cast_to.is_usize() {
                 let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability);
                 span_lint_and_sugg(
                     cx,
diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs
index 700b7d0d426..4da79205e20 100644
--- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs
@@ -17,7 +17,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
             let mut applicability = Applicability::MaybeIncorrect;
             let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability);
 
-            if to_nbits < cx.tcx.data_layout.pointer_size.bits() {
+            if to_nbits < cx.tcx.data_layout.pointer_size().bits() {
                 span_lint_and_sugg(
                     cx,
                     FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
diff --git a/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs
index d9e88d6a401..92910cf8adf 100644
--- a/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs
@@ -46,7 +46,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, from: &Expr<'_>, to:
 fn is_expr_const_aligned(cx: &LateContext<'_>, expr: &Expr<'_>, to: &Ty<'_>) -> bool {
     match expr.kind {
         ExprKind::Call(fun, _) => is_align_of_call(cx, fun, to),
-        ExprKind::Lit(lit) => is_literal_aligned(cx, lit, to),
+        ExprKind::Lit(lit) => is_literal_aligned(cx, &lit, to),
         _ => false,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
index 010f09d4c1d..c88a0539d70 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -243,7 +243,7 @@ fn lint_unnecessary_cast(
     );
 }
 
-fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option<&'e Lit> {
+fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option<Lit> {
     match expr.kind {
         ExprKind::Lit(lit) => Some(lit),
         ExprKind::Unary(UnOp::Neg, e) => {
diff --git a/src/tools/clippy/clippy_lints/src/casts/utils.rs b/src/tools/clippy/clippy_lints/src/casts/utils.rs
index 318a1646477..d846d78b9ee 100644
--- a/src/tools/clippy/clippy_lints/src/casts/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/utils.rs
@@ -5,7 +5,7 @@ use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TyCtxt, UintTy, VariantDiscr};
 /// integral type.
 pub(super) fn int_ty_to_nbits(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<u64> {
     match ty.kind() {
-        ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Some(tcx.data_layout.pointer_size.bits()),
+        ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Some(tcx.data_layout.pointer_size().bits()),
         ty::Int(i) => i.bit_width(),
         ty::Uint(i) => i.bit_width(),
         _ => None,
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index 784214c29af..1507f1ed305 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -83,7 +83,7 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
     }
 
     /// Check whether a passed literal has potential to cause fallback or not.
-    fn check_lit(&self, lit: &Lit, lit_ty: Ty<'tcx>, emit_hir_id: HirId) {
+    fn check_lit(&self, lit: Lit, lit_ty: Ty<'tcx>, emit_hir_id: HirId) {
         if !lit.span.in_external_macro(self.cx.sess().source_map())
             && matches!(self.ty_bounds.last(), Some(ExplicitTyBound(false)))
             && matches!(
@@ -210,7 +210,7 @@ impl<'tcx> Visitor<'tcx> for NumericFallbackVisitor<'_, 'tcx> {
 
             ExprKind::Lit(lit) => {
                 let ty = self.cx.typeck_results().expr_ty(expr);
-                self.check_lit(lit, ty, expr.hir_id);
+                self.check_lit(*lit, ty, expr.hir_id);
                 return;
             },
 
diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
index 615421f3a40..9bf2144e445 100644
--- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
@@ -99,5 +99,5 @@ fn is_zst<'tcx>(cx: &LateContext<'tcx>, field: &FieldDef, args: ty::GenericArgsR
 fn has_c_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool {
     let attrs = cx.tcx.hir_attrs(hir_id);
 
-    find_attr!(attrs, AttributeKind::Repr(r) if r.iter().any(|(x, _)| *x == ReprAttr::ReprC))
+    find_attr!(attrs, AttributeKind::Repr { reprs, .. } if reprs.iter().any(|(x, _)| *x == ReprAttr::ReprC))
 }
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 7463d7b5c3b..5099df3fa02 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -824,7 +824,7 @@ impl TyCoercionStability {
                 TyKind::Slice(_)
                 | TyKind::Array(..)
                 | TyKind::Ptr(_)
-                | TyKind::BareFn(_)
+                | TyKind::FnPtr(_)
                 | TyKind::Pat(..)
                 | TyKind::Never
                 | TyKind::Tup(_)
diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs
index 098571a5351..c828fc57f76 100644
--- a/src/tools/clippy/clippy_lints/src/enum_clike.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs
@@ -35,7 +35,7 @@ declare_lint_pass!(UnportableVariant => [ENUM_CLIKE_UNPORTABLE_VARIANT]);
 impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
     #[expect(clippy::cast_possible_wrap)]
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if cx.tcx.data_layout.pointer_size.bits() != 64 {
+        if cx.tcx.data_layout.pointer_size().bits() != 64 {
             return;
         }
         if let ItemKind::Enum(_, _, def) = &item.kind {
diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
index 86d9038ec45..7dda3e0fdb9 100644
--- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
+++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
@@ -4,7 +4,9 @@ use rustc_errors::Applicability;
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
+use rustc_attr_data_structures::AttributeKind;
+use rustc_attr_data_structures::find_attr;
+
 
 declare_clippy_lint! {
     /// ### What it does
@@ -85,7 +87,7 @@ impl LateLintPass<'_> for ExhaustiveItems {
         };
         if cx.effective_visibilities.is_exported(item.owner_id.def_id)
             && let attrs = cx.tcx.hir_attrs(item.hir_id())
-            && !attrs.iter().any(|a| a.has_name(sym::non_exhaustive))
+            && !find_attr!(attrs, AttributeKind::NonExhaustive(..))
             && fields.iter().all(|f| cx.tcx.visibility(f.def_id).is_public())
         {
             span_lint_and_then(cx, lint, item.span, msg, |diag| {
diff --git a/src/tools/clippy/clippy_lints/src/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs
index 621a2af1d32..8707612fbdd 100644
--- a/src/tools/clippy/clippy_lints/src/large_include_file.rs
+++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs
@@ -57,7 +57,7 @@ impl LateLintPass<'_> for LargeIncludeFile {
         if let ExprKind::Lit(lit) = &expr.kind
             && let len = match &lit.node {
                 // include_bytes
-                LitKind::ByteStr(bstr, _) => bstr.len(),
+                LitKind::ByteStr(bstr, _) => bstr.as_byte_str().len(),
                 // include_str
                 LitKind::Str(sym, _) => sym.as_str().len(),
                 _ => return,
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 8fe0c9d60f9..caf17c10484 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -13,7 +13,7 @@ use rustc_hir::intravisit::{
     walk_poly_trait_ref, walk_trait_ref, walk_ty, walk_unambig_ty, walk_where_predicate,
 };
 use rustc_hir::{
-    AmbigArg, BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind,
+    AmbigArg, BodyId, FnDecl, FnPtrTy, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind,
     Generics, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeKind, LifetimeParamKind, Node,
     PolyTraitRef, PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WhereBoundPredicate, WherePredicate,
     WherePredicateKind, lang_items,
@@ -480,7 +480,7 @@ impl<'tcx> Visitor<'tcx> for RefVisitor<'_, 'tcx> {
 
     fn visit_ty(&mut self, ty: &'tcx Ty<'_, AmbigArg>) {
         match ty.kind {
-            TyKind::BareFn(&BareFnTy { decl, .. }) => {
+            TyKind::FnPtr(&FnPtrTy { decl, .. }) => {
                 let mut sub_visitor = RefVisitor::new(self.cx);
                 sub_visitor.visit_fn_decl(decl);
                 self.nested_elision_site_lts.append(&mut sub_visitor.all_lts());
diff --git a/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs b/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs
index 57c03fbb2ed..f7d9ec1fae8 100644
--- a/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs
@@ -41,12 +41,12 @@ declare_clippy_lint! {
 
 declare_lint_pass!(ManualIgnoreCaseCmp => [MANUAL_IGNORE_CASE_CMP]);
 
-enum MatchType<'a, 'b> {
+enum MatchType<'a> {
     ToAscii(bool, Ty<'a>),
-    Literal(&'b LitKind),
+    Literal(LitKind),
 }
 
-fn get_ascii_type<'a, 'b>(cx: &LateContext<'a>, kind: rustc_hir::ExprKind<'b>) -> Option<(Span, MatchType<'a, 'b>)> {
+fn get_ascii_type<'a>(cx: &LateContext<'a>, kind: rustc_hir::ExprKind<'_>) -> Option<(Span, MatchType<'a>)> {
     if let MethodCall(path, expr, _, _) = kind {
         let is_lower = match path.ident.name {
             sym::to_ascii_lowercase => true,
@@ -63,7 +63,7 @@ fn get_ascii_type<'a, 'b>(cx: &LateContext<'a>, kind: rustc_hir::ExprKind<'b>) -
             return Some((expr.span, ToAscii(is_lower, ty_raw)));
         }
     } else if let Lit(expr) = kind {
-        return Some((expr.span, Literal(&expr.node)));
+        return Some((expr.span, Literal(expr.node)));
     }
     None
 }
diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
index 3562b1ff5cc..51696b38880 100644
--- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
@@ -4,7 +4,6 @@ use clippy_utils::is_doc_hidden;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_indent;
 use itertools::Itertools;
-use rustc_ast::attr;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
@@ -12,7 +11,9 @@ use rustc_hir::{Expr, ExprKind, Item, ItemKind, QPath, TyKind, VariantData};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
 use rustc_span::def_id::LocalDefId;
-use rustc_span::{Span, sym};
+use rustc_span::Span;
+use rustc_attr_data_structures::find_attr;
+use rustc_attr_data_structures::AttributeKind;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -93,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive {
                         .then_some((v.def_id, v.span))
                 });
                 if let Ok((id, span)) = iter.exactly_one()
-                    && !attr::contains_name(cx.tcx.hir_attrs(item.hir_id()), sym::non_exhaustive)
+                    && !find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::NonExhaustive(..))
                 {
                     self.potential_enums.push((item.owner_id.def_id, id, item.span, span));
                 }
@@ -113,10 +114,10 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive {
                         item.span,
                         "this seems like a manual implementation of the non-exhaustive pattern",
                         |diag| {
-                            if let Some(non_exhaustive) =
-                                attr::find_by_name(cx.tcx.hir_attrs(item.hir_id()), sym::non_exhaustive)
+                            if let Some(non_exhaustive_span) =
+                                find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::NonExhaustive(span) => *span)
                             {
-                                diag.span_note(non_exhaustive.span(), "the struct is already non-exhaustive");
+                                diag.span_note(non_exhaustive_span, "the struct is already non-exhaustive");
                             } else {
                                 let indent = snippet_indent(cx, item.span).unwrap_or_default();
                                 diag.span_suggestion_verbose(
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index 9e911e61f19..6bf43a1c6d4 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -184,7 +184,7 @@ fn eq_pattern_length<'tcx>(cx: &LateContext<'tcx>, pattern: &Expr<'_>, expr: &'t
         ..
     }) = expr.kind
     {
-        constant_length(cx, pattern).is_some_and(|length| *n == length)
+        constant_length(cx, pattern).is_some_and(|length| n == length)
     } else {
         len_arg(cx, expr).is_some_and(|arg| eq_expr_value(cx, pattern, arg))
     }
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
index f14b69d91ce..5816da5695e 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
@@ -159,7 +159,7 @@ fn find_bool_lit(ex: &ExprKind<'_>) -> Option<bool> {
                 node: LitKind::Bool(b), ..
             }) = exp.kind
             {
-                Some(*b)
+                Some(b)
             } else {
                 None
             }
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index dbb29ee776b..ede68f30941 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -12,7 +12,7 @@ use rustc_hir::{Arm, Expr, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatExp
 use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::ty;
-use rustc_span::{ErrorGuaranteed, Span, Symbol};
+use rustc_span::{ByteSymbol, ErrorGuaranteed, Span, Symbol};
 
 use super::MATCH_SAME_ARMS;
 
@@ -193,7 +193,7 @@ enum NormalizedPat<'a> {
     Or(&'a [Self]),
     Path(Option<DefId>),
     LitStr(Symbol),
-    LitBytes(&'a [u8]),
+    LitBytes(ByteSymbol),
     LitInt(u128),
     LitBool(bool),
     Range(PatRange),
@@ -332,7 +332,9 @@ impl<'a> NormalizedPat<'a> {
                 // TODO: Handle negative integers. They're currently treated as a wild match.
                 PatExprKind::Lit { lit, negated: false } => match lit.node {
                     LitKind::Str(sym, _) => Self::LitStr(sym),
-                    LitKind::ByteStr(ref bytes, _) | LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes),
+                    LitKind::ByteStr(byte_sym, _) | LitKind::CStr(byte_sym, _) => {
+                        Self::LitBytes(byte_sym)
+                    }
                     LitKind::Byte(val) => Self::LitInt(val.into()),
                     LitKind::Char(val) => Self::LitInt(val.into()),
                     LitKind::Int(val, _) => Self::LitInt(val.get()),
diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
index fd368024177..9b5f138295c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
@@ -76,7 +76,7 @@ fn get_open_options(
                         ..
                     } = span
                     {
-                        Argument::Set(*lit)
+                        Argument::Set(lit)
                     } else {
                         // The function is called with a literal which is not a boolean literal.
                         // This is theoretically possible, but not very likely.
diff --git a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs
index c8e3462b24e..cf0c85990b1 100644
--- a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs
@@ -104,7 +104,7 @@ fn len_comparison<'hir>(
 ) -> Option<(LengthComparison, usize, &'hir Expr<'hir>)> {
     macro_rules! int_lit_pat {
         ($id:ident) => {
-            ExprKind::Lit(&Spanned {
+            ExprKind::Lit(Spanned {
                 node: LitKind::Int(Pu128($id), _),
                 ..
             })
diff --git a/src/tools/clippy/clippy_lints/src/types/type_complexity.rs b/src/tools/clippy/clippy_lints/src/types/type_complexity.rs
index 0704653385f..52c6fda8097 100644
--- a/src/tools/clippy/clippy_lints/src/types/type_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/types/type_complexity.rs
@@ -50,7 +50,7 @@ impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor {
             TyKind::Path(..) | TyKind::Slice(..) | TyKind::Tup(..) | TyKind::Array(..) => (10 * self.nest, 1),
 
             // function types bring a lot of overhead
-            TyKind::BareFn(bare) if bare.abi == ExternAbi::Rust => (50 * self.nest, 1),
+            TyKind::FnPtr(fn_ptr) if fn_ptr.abi == ExternAbi::Rust => (50 * self.nest, 1),
 
             TyKind::TraitObject(param_bounds, _) => {
                 let has_lifetime_parameters = param_bounds.iter().any(|bound| {
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index 92427473a8e..6cc4b589a72 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -256,7 +256,10 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
                             cx,
                             UNNECESSARY_SAFETY_COMMENT,
                             span,
-                            format!("{} has unnecessary safety comment", item.kind.descr()),
+                            format!(
+                                "{} has unnecessary safety comment",
+                                cx.tcx.def_descr(item.owner_id.to_def_id()),
+                            ),
                             |diag| {
                                 diag.span_help(help_span, "consider removing the safety comment");
                             },
@@ -274,7 +277,10 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
                         cx,
                         UNNECESSARY_SAFETY_COMMENT,
                         span,
-                        format!("{} has unnecessary safety comment", item.kind.descr()),
+                        format!(
+                            "{} has unnecessary safety comment",
+                            cx.tcx.def_descr(item.owner_id.to_def_id()),
+                        ),
                         |diag| {
                             diag.span_help(help_span, "consider removing the safety comment");
                         },
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 3a08531cf1c..ac92ab5a245 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -324,7 +324,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
         }
     }
 
-    fn lit(&self, lit: &Binding<&Lit>) {
+    fn lit(&self, lit: &Binding<Lit>) {
         let kind = |kind| chain!(self, "let LitKind::{kind} = {lit}.node");
         macro_rules! kind {
             ($($t:tt)*) => (kind(format_args!($($t)*)));
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index d9dda6eadb2..22fd15d153a 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -130,7 +130,7 @@ impl LateLintPass<'_> for WildcardImports {
         }
         if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind
             && (self.warn_on_all || !self.check_exceptions(cx, item, use_path.segments))
-            && let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id)
+            && let Some(used_imports) = cx.tcx.resolutions(()).glob_map.get(&item.owner_id.def_id)
             && !used_imports.is_empty() // Already handled by `unused_imports`
             && !used_imports.contains(&kw::Underscore)
         {
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
index e65914b9b5e..42254ec8e92 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
@@ -838,7 +838,7 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool {
         (PinnedRef(ll, l), PinnedRef(rl, r)) => {
             both(ll.as_ref(), rl.as_ref(), |l, r| eq_id(l.ident, r.ident)) && l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty)
         },
-        (BareFn(l), BareFn(r)) => {
+        (FnPtr(l), FnPtr(r)) => {
             l.safety == r.safety
                 && eq_ext(&l.ext, &r.ext)
                 && over(&l.generic_params, &r.generic_params, eq_generic_param)
@@ -886,13 +886,13 @@ pub fn eq_generic_param(l: &GenericParam, r: &GenericParam) -> bool {
             (
                 Const {
                     ty: lt,
-                    kw_span: _,
                     default: ld,
+                    span: _,
                 },
                 Const {
                     ty: rt,
-                    kw_span: _,
                     default: rd,
+                    span: _,
                 },
             ) => eq_ty(lt, rt) && both(ld.as_ref(), rd.as_ref(), eq_anon_const),
             _ => false,
diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs
index 8a0ff5323c9..4c7a589e185 100644
--- a/src/tools/clippy/clippy_utils/src/attrs.rs
+++ b/src/tools/clippy/clippy_utils/src/attrs.rs
@@ -7,9 +7,10 @@ use rustc_middle::ty::{AdtDef, TyCtxt};
 use rustc_session::Session;
 use rustc_span::{Span, Symbol};
 use std::str::FromStr;
-
+use rustc_attr_data_structures::find_attr;
 use crate::source::SpanRangeExt;
 use crate::{sym, tokenize_with_text};
+use rustc_attr_data_structures::AttributeKind;
 
 /// Deprecation status of attributes known by Clippy.
 pub enum DeprecationStatus {
@@ -165,13 +166,13 @@ pub fn is_doc_hidden(attrs: &[impl AttributeExt]) -> bool {
 
 pub fn has_non_exhaustive_attr(tcx: TyCtxt<'_>, adt: AdtDef<'_>) -> bool {
     adt.is_variant_list_non_exhaustive()
-        || tcx.has_attr(adt.did(), sym::non_exhaustive)
+        || find_attr!(tcx.get_all_attrs(adt.did()), AttributeKind::NonExhaustive(..))
         || adt.variants().iter().any(|variant_def| {
-            variant_def.is_field_list_non_exhaustive() || tcx.has_attr(variant_def.def_id, sym::non_exhaustive)
+            variant_def.is_field_list_non_exhaustive() || find_attr!(tcx.get_all_attrs(variant_def.def_id), AttributeKind::NonExhaustive(..))
         })
         || adt
             .all_fields()
-            .any(|field_def| tcx.has_attr(field_def.did, sym::non_exhaustive))
+            .any(|field_def| find_attr!(tcx.get_all_attrs(field_def.did), AttributeKind::NonExhaustive(..)))
 }
 
 /// Checks if the given span contains a `#[cfg(..)]` attribute
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index 407e92d88fb..ce61fffe0de 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -372,17 +372,17 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) {
         TyKind::Slice(..) | TyKind::Array(..) => (Pat::Str("["), Pat::Str("]")),
         TyKind::Ptr(MutTy { ty, .. }) => (Pat::Str("*"), ty_search_pat(ty).1),
         TyKind::Ref(_, MutTy { ty, .. }) => (Pat::Str("&"), ty_search_pat(ty).1),
-        TyKind::BareFn(bare_fn) => (
-            if bare_fn.safety.is_unsafe() {
+        TyKind::FnPtr(fn_ptr) => (
+            if fn_ptr.safety.is_unsafe() {
                 Pat::Str("unsafe")
-            } else if bare_fn.abi != ExternAbi::Rust {
+            } else if fn_ptr.abi != ExternAbi::Rust {
                 Pat::Str("extern")
             } else {
                 Pat::MultiStr(&["fn", "extern"])
             },
-            match bare_fn.decl.output {
+            match fn_ptr.decl.output {
                 FnRetTy::DefaultReturn(_) => {
-                    if let [.., ty] = bare_fn.decl.inputs {
+                    if let [.., ty] = fn_ptr.decl.inputs {
                         ty_search_pat(ty).1
                     } else {
                         Pat::Str("(")
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index aaa071fd5c9..ba0376e4d40 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -4,8 +4,6 @@
 //! executable MIR bodies, so we have to do this instead.
 #![allow(clippy::float_cmp)]
 
-use std::sync::Arc;
-
 use crate::source::{SpanRangeExt, walk_span_to_context};
 use crate::{clip, is_direct_expn_of, sext, unsext};
 
@@ -38,7 +36,7 @@ pub enum Constant<'tcx> {
     /// A `String` (e.g., "abc").
     Str(String),
     /// A binary string (e.g., `b"abc"`).
-    Binary(Arc<[u8]>),
+    Binary(Vec<u8>),
     /// A single `char` (e.g., `'a'`).
     Char(char),
     /// An integer's bit representation.
@@ -306,7 +304,9 @@ pub fn lit_to_mir_constant<'tcx>(lit: &LitKind, ty: Option<Ty<'tcx>>) -> Constan
     match *lit {
         LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
         LitKind::Byte(b) => Constant::Int(u128::from(b)),
-        LitKind::ByteStr(ref s, _) | LitKind::CStr(ref s, _) => Constant::Binary(Arc::clone(s)),
+        LitKind::ByteStr(ref s, _) | LitKind::CStr(ref s, _) => {
+            Constant::Binary(s.as_byte_str().to_vec())
+        }
         LitKind::Char(c) => Constant::Char(c),
         LitKind::Int(n, _) => Constant::Int(n.get()),
         LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty {
@@ -568,7 +568,9 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
                 } else {
                     match &lit.node {
                         LitKind::Str(is, _) => Some(is.is_empty()),
-                        LitKind::ByteStr(s, _) | LitKind::CStr(s, _) => Some(s.is_empty()),
+                        LitKind::ByteStr(s, _) | LitKind::CStr(s, _) => {
+                            Some(s.as_byte_str().is_empty())
+                        }
                         _ => None,
                     }
                 }
@@ -916,7 +918,7 @@ fn mir_is_empty<'tcx>(tcx: TyCtxt<'tcx>, result: mir::Const<'tcx>) -> Option<boo
                     // Get the length from the slice, using the same formula as
                     // [`ConstValue::try_get_slice_bytes_for_diagnostics`].
                     let a = tcx.global_alloc(alloc_id).unwrap_memory().inner();
-                    let ptr_size = tcx.data_layout.pointer_size;
+                    let ptr_size = tcx.data_layout.pointer_size();
                     if a.size() < offset + 2 * ptr_size {
                         // (partially) dangling reference
                         return None;
diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs
index dc240dd067b..8453165818b 100644
--- a/src/tools/clippy/clippy_utils/src/diagnostics.rs
+++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs
@@ -98,6 +98,7 @@ fn validate_diag(diag: &Diag<'_, impl EmissionGuarantee>) {
 /// 17 |     std::mem::forget(seven);
 ///    |     ^^^^^^^^^^^^^^^^^^^^^^^
 /// ```
+#[track_caller]
 pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
     #[expect(clippy::disallowed_methods)]
     cx.span_lint(lint, sp, |diag| {
@@ -143,6 +144,7 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult
 ///    |
 ///    = help: consider using `f64::NAN` if you would like a constant representing NaN
 /// ```
+#[track_caller]
 pub fn span_lint_and_help<T: LintContext>(
     cx: &T,
     lint: &'static Lint,
@@ -203,6 +205,7 @@ pub fn span_lint_and_help<T: LintContext>(
 /// 10 |     forget(&SomeStruct);
 ///    |            ^^^^^^^^^^^
 /// ```
+#[track_caller]
 pub fn span_lint_and_note<T: LintContext>(
     cx: &T,
     lint: &'static Lint,
@@ -244,6 +247,7 @@ pub fn span_lint_and_note<T: LintContext>(
 /// If you're unsure which function you should use, you can test if the `#[expect]` attribute works
 /// where you would expect it to.
 /// If it doesn't, you likely need to use [`span_lint_hir_and_then`] instead.
+#[track_caller]
 pub fn span_lint_and_then<C, S, M, F>(cx: &C, lint: &'static Lint, sp: S, msg: M, f: F)
 where
     C: LintContext,
@@ -286,6 +290,7 @@ where
 /// Instead, use this function and also pass the `HirId` of `<expr_1>`, which will let
 /// the compiler check lint level attributes at the place of the expression and
 /// the `#[allow]` will work.
+#[track_caller]
 pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: impl Into<DiagMessage>) {
     #[expect(clippy::disallowed_methods)]
     cx.tcx.node_span_lint(lint, hir_id, sp, |diag| {
@@ -321,6 +326,7 @@ pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, s
 /// Instead, use this function and also pass the `HirId` of `<expr_1>`, which will let
 /// the compiler check lint level attributes at the place of the expression and
 /// the `#[allow]` will work.
+#[track_caller]
 pub fn span_lint_hir_and_then(
     cx: &LateContext<'_>,
     lint: &'static Lint,
@@ -374,6 +380,7 @@ pub fn span_lint_hir_and_then(
 ///     = note: `-D fold-any` implied by `-D warnings`
 /// ```
 #[cfg_attr(not(debug_assertions), expect(clippy::collapsible_span_lint_calls))]
+#[track_caller]
 pub fn span_lint_and_sugg<T: LintContext>(
     cx: &T,
     lint: &'static Lint,
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index c37231d0931..0ca494f16e3 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -1283,20 +1283,20 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 self.hash_ty(mut_ty.ty);
                 mut_ty.mutbl.hash(&mut self.s);
             },
-            TyKind::BareFn(bfn) => {
-                bfn.safety.hash(&mut self.s);
-                bfn.abi.hash(&mut self.s);
-                for arg in bfn.decl.inputs {
+            TyKind::FnPtr(fn_ptr) => {
+                fn_ptr.safety.hash(&mut self.s);
+                fn_ptr.abi.hash(&mut self.s);
+                for arg in fn_ptr.decl.inputs {
                     self.hash_ty(arg);
                 }
-                std::mem::discriminant(&bfn.decl.output).hash(&mut self.s);
-                match bfn.decl.output {
+                std::mem::discriminant(&fn_ptr.decl.output).hash(&mut self.s);
+                match fn_ptr.decl.output {
                     FnRetTy::DefaultReturn(_) => {},
                     FnRetTy::Return(ty) => {
                         self.hash_ty(ty);
                     },
                 }
-                bfn.decl.c_variadic.hash(&mut self.s);
+                fn_ptr.decl.c_variadic.hash(&mut self.s);
             },
             TyKind::Tup(ty_list) => {
                 for ty in *ty_list {
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index a8b33418c8c..c01f0ffaac9 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1761,7 +1761,7 @@ pub fn has_attr(attrs: &[hir::Attribute], symbol: Symbol) -> bool {
 }
 
 pub fn has_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool {
-    find_attr!(cx.tcx.hir_attrs(hir_id), AttributeKind::Repr(..))
+    find_attr!(cx.tcx.hir_attrs(hir_id), AttributeKind::Repr { .. })
 }
 
 pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool {
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 8f1ebb8ada6..942c71ac33b 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
@@ -175,10 +175,6 @@ fn check_rvalue<'tcx>(
         Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => {
             Err((span, "casting pointers to ints is unstable in const fn".into()))
         },
-        Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::DynStar, _), _, _) => {
-            // FIXME(dyn-star)
-            unimplemented!()
-        },
         Rvalue::Cast(CastKind::Transmute, _, _) => Err((
             span,
             "transmute can attempt to turn pointers into integers, so is unstable in const fn".into(),
diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr
index 8a2f201009a..bfc14be5421 100644
--- a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr
+++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr
@@ -240,7 +240,7 @@ LL |     unsafe impl TrailingComment for () {} // SAFETY:
    |
    = help: consider adding a safety comment on the preceding line
 
-error: constant item has unnecessary safety comment
+error: constant has unnecessary safety comment
   --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:508:5
    |
 LL |     const BIG_NUMBER: i32 = 1000000;
diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr
index e9c5e5f9f11..20cdff5fcd1 100644
--- a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr
+++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr
@@ -240,7 +240,7 @@ LL |     unsafe impl TrailingComment for () {} // SAFETY:
    |
    = help: consider adding a safety comment on the preceding line
 
-error: constant item has unnecessary safety comment
+error: constant has unnecessary safety comment
   --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:508:5
    |
 LL |     const BIG_NUMBER: i32 = 1000000;
diff --git a/src/tools/clippy/tests/ui/track-diagnostics-clippy.rs b/src/tools/clippy/tests/ui/track-diagnostics-clippy.rs
new file mode 100644
index 00000000000..2e67fb65efc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/track-diagnostics-clippy.rs
@@ -0,0 +1,22 @@
+//@compile-flags: -Z track-diagnostics
+//@no-rustfix
+
+// Normalize the emitted location so this doesn't need
+// updating everytime someone adds or removes a line.
+//@normalize-stderr-test: ".rs:\d+:\d+" -> ".rs:LL:CC"
+
+#![warn(clippy::let_and_return, clippy::unnecessary_cast)]
+
+fn main() {
+    // Check the provenance of a lint sent through `LintContext::span_lint()`
+    let a = 3u32;
+    let b = a as u32;
+    //~^ unnecessary_cast
+    
+    // Check the provenance of a lint sent through `TyCtxt::node_span_lint()`
+    let c = {
+        let d = 42;
+        d
+        //~^ let_and_return
+    };
+}
diff --git a/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr b/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr
new file mode 100644
index 00000000000..9d6538112bf
--- /dev/null
+++ b/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr
@@ -0,0 +1,29 @@
+error: casting to the same type is unnecessary (`u32` -> `u32`)
+  --> tests/ui/track-diagnostics-clippy.rs:LL:CC
+   |
+LL |     let b = a as u32;
+   |             ^^^^^^^^ help: try: `a`
+   |
+   = note: -Ztrack-diagnostics: created at src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs:LL:CC
+   = note: `-D clippy::unnecessary-cast` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::unnecessary_cast)]`
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/track-diagnostics-clippy.rs:LL:CC
+   |
+LL |         let d = 42;
+   |         ----------- unnecessary `let` binding
+LL |         d
+   |         ^
+   |
+   = note: -Ztrack-diagnostics: created at src/tools/clippy/clippy_lints/src/returns.rs:LL:CC
+   = note: `-D clippy::let-and-return` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::let_and_return)]`
+help: return the expression directly
+   |
+LL ~         
+LL ~         42
+   |
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/track-diagnostics.rs b/src/tools/clippy/tests/ui/track-diagnostics.rs
index 723ea23e9a6..0fbde867390 100644
--- a/src/tools/clippy/tests/ui/track-diagnostics.rs
+++ b/src/tools/clippy/tests/ui/track-diagnostics.rs
@@ -8,5 +8,6 @@ struct A;
 struct B;
 const S: A = B;
 //~^ ERROR: mismatched types
+//~| NOTE: created at
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/track-diagnostics.stderr b/src/tools/clippy/tests/ui/track-diagnostics.stderr
index 83451fb658d..45262ba618f 100644
--- a/src/tools/clippy/tests/ui/track-diagnostics.stderr
+++ b/src/tools/clippy/tests/ui/track-diagnostics.stderr
@@ -3,7 +3,8 @@ error[E0308]: mismatched types
    |
 LL | const S: A = B;
    |              ^ expected `A`, found `B`
--Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs:LL:CC
+   |
+   = note: -Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs:LL:CC
 
 error: aborting due to 1 previous error
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_safety_comment.stderr b/src/tools/clippy/tests/ui/unnecessary_safety_comment.stderr
index b56e8b35493..732e6767c17 100644
--- a/src/tools/clippy/tests/ui/unnecessary_safety_comment.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_safety_comment.stderr
@@ -1,4 +1,4 @@
-error: constant item has unnecessary safety comment
+error: constant has unnecessary safety comment
   --> tests/ui/unnecessary_safety_comment.rs:6:5
    |
 LL |     const CONST: u32 = 0;
@@ -12,7 +12,7 @@ LL |     // SAFETY:
    = note: `-D clippy::unnecessary-safety-comment` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_comment)]`
 
-error: static item has unnecessary safety comment
+error: static has unnecessary safety comment
   --> tests/ui/unnecessary_safety_comment.rs:10:5
    |
 LL |     static STATIC: u32 = 0;
diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml
index 3b544d8b828..cdada5a2230 100644
--- a/src/tools/compiletest/Cargo.toml
+++ b/src/tools/compiletest/Cargo.toml
@@ -6,6 +6,10 @@ edition = "2024"
 [lib]
 doctest = false
 
+[[bin]]
+name = "compiletest"
+path = "src/bin/main.rs"
+
 [dependencies]
 # tidy-alphabetical-start
 anstyle-svg = "0.1.3"
diff --git a/src/tools/compiletest/src/bin/main.rs b/src/tools/compiletest/src/bin/main.rs
new file mode 100644
index 00000000000..1f777e71cf9
--- /dev/null
+++ b/src/tools/compiletest/src/bin/main.rs
@@ -0,0 +1,24 @@
+use std::env;
+use std::io::IsTerminal;
+use std::sync::Arc;
+
+use compiletest::{early_config_check, log_config, parse_config, run_tests};
+
+fn main() {
+    tracing_subscriber::fmt::init();
+
+    // colored checks stdout by default, but for some reason only stderr is a terminal.
+    // compiletest *does* print many things to stdout, but it doesn't really matter.
+    if std::io::stderr().is_terminal()
+        && matches!(std::env::var("NO_COLOR").as_deref(), Err(_) | Ok("0"))
+    {
+        colored::control::set_override(true);
+    }
+
+    let config = Arc::new(parse_config(env::args().collect()));
+
+    early_config_check(&config);
+
+    log_config(&config);
+    run_tests(config);
+}
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 9b9d94bbead..7122746fa87 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -11,6 +11,7 @@ use serde::de::{Deserialize, Deserializer, Error as _};
 
 pub use self::Mode::*;
 use crate::executor::{ColorConfig, OutputFormat};
+use crate::fatal;
 use crate::util::{Utf8PathBufExt, add_dylib_path};
 
 macro_rules! string_enum {
@@ -171,207 +172,422 @@ pub enum Sanitizer {
     Hwaddress,
 }
 
-/// Configuration for compiletest
+/// Configuration for `compiletest` *per invocation*.
+///
+/// In terms of `bootstrap`, this means that `./x test tests/ui tests/run-make` actually correspond
+/// to *two* separate invocations of `compiletest`.
+///
+/// FIXME: this `Config` struct should be broken up into smaller logically contained sub-config
+/// structs, it's too much of a "soup" of everything at the moment.
+///
+/// # Configuration sources
+///
+/// Configuration values for `compiletest` comes from several sources:
+///
+/// - CLI args passed from `bootstrap` while running the `compiletest` binary.
+/// - Env vars.
+/// - Discovery (e.g. trying to identify a suitable debugger based on filesystem discovery).
+/// - Cached output of running the `rustc` under test (e.g. output of `rustc` print requests).
+///
+/// FIXME: make sure we *clearly* account for sources of *all* config options.
+///
+/// FIXME: audit these options to make sure we are not hashing less than necessary for build stamp
+/// (for changed test detection).
 #[derive(Debug, Default, Clone)]
 pub struct Config {
-    /// `true` to overwrite stderr/stdout files instead of complaining about changes in output.
+    /// Some test [`Mode`]s support [snapshot testing], where a *reference snapshot* of outputs (of
+    /// `stdout`, `stderr`, or other form of artifacts) can be compared to the *actual output*.
+    ///
+    /// This option can be set to `true` to update the *reference snapshots* in-place, otherwise
+    /// `compiletest` will only try to compare.
+    ///
+    /// [snapshot testing]: https://jestjs.io/docs/snapshot-testing
     pub bless: bool,
 
-    /// Stop as soon as possible after any test fails.
-    /// May run a few more tests before stopping, due to threading.
+    /// Attempt to stop as soon as possible after any test fails. We may still run a few more tests
+    /// before stopping when multiple test threads are used.
     pub fail_fast: bool,
 
-    /// The library paths required for running the compiler.
+    /// Path to libraries needed to run the *staged* `rustc`-under-test on the **host** platform.
+    ///
+    /// FIXME: maybe rename this to reflect (1) which target platform (host, not target), and (2)
+    /// which `rustc` (the `rustc`-under-test, not the stage 0 `rustc` unless forced).
     pub compile_lib_path: Utf8PathBuf,
 
-    /// The library paths required for running compiled programs.
+    /// Path to libraries needed to run the compiled executable for the **target** platform. This
+    /// corresponds to the **target** sysroot libraries, including the **target** standard library.
+    ///
+    /// FIXME: maybe rename this to reflect (1) which target platform (target, not host), and (2)
+    /// what "run libraries" are against.
+    ///
+    /// FIXME: this is very under-documented in conjunction with the `remote-test-client` scheme and
+    /// `RUNNER` scheme to actually run the target executable under the target platform environment,
+    /// cf. [`Self::remote_test_client`] and [`Self::runner`].
     pub run_lib_path: Utf8PathBuf,
 
-    /// The rustc executable.
+    /// Path to the *staged*  `rustc`-under-test. Unless forced, this `rustc` is *staged*, and must
+    /// not be confused with [`Self::stage0_rustc_path`].
+    ///
+    /// FIXME: maybe rename this to reflect that this is the `rustc`-under-test.
     pub rustc_path: Utf8PathBuf,
 
-    /// The cargo executable.
+    /// Path to a *staged* **host** platform cargo executable (unless stage 0 is forced). This
+    /// staged `cargo` is only used within `run-make` test recipes during recipe run time (and is
+    /// *not* used to compile the test recipes), and so must be staged as there may be differences
+    /// between e.g. beta `cargo` vs in-tree `cargo`.
+    ///
+    /// FIXME: maybe rename this to reflect that this is a *staged* host cargo.
+    ///
+    /// FIXME(#134109): split `run-make` into two test suites, a test suite *with* staged cargo, and
+    /// another test suite *without*.
     pub cargo_path: Option<Utf8PathBuf>,
 
-    /// Rustc executable used to compile run-make recipes.
+    /// Path to the stage 0 `rustc` used to build `run-make` recipes. This must not be confused with
+    /// [`Self::rustc_path`].
     pub stage0_rustc_path: Option<Utf8PathBuf>,
 
-    /// The rustdoc executable.
+    /// Path to the `rustdoc`-under-test. Like [`Self::rustc_path`], this `rustdoc` is *staged*.
     pub rustdoc_path: Option<Utf8PathBuf>,
 
-    /// The coverage-dump executable.
+    /// Path to the `src/tools/coverage-dump/` bootstrap tool executable.
     pub coverage_dump_path: Option<Utf8PathBuf>,
 
-    /// The Python executable to use for LLDB and htmldocck.
+    /// Path to the Python 3 executable to use for LLDB and htmldocck.
+    ///
+    /// FIXME: the `lldb` setup currently requires I believe Python 3.10 **exactly**, it can't even
+    /// be Python 3.11 or 3.9...
     pub python: String,
 
-    /// The jsondocck executable.
+    /// Path to the `src/tools/jsondocck/` bootstrap tool executable.
     pub jsondocck_path: Option<String>,
 
-    /// The jsondoclint executable.
+    /// Path to the `src/tools/jsondoclint/` bootstrap tool executable.
     pub jsondoclint_path: Option<String>,
 
-    /// The LLVM `FileCheck` binary path.
+    /// Path to a host LLVM `FileCheck` executable.
     pub llvm_filecheck: Option<Utf8PathBuf>,
 
-    /// Path to LLVM's bin directory.
+    /// Path to a host LLVM bintools directory.
     pub llvm_bin_dir: Option<Utf8PathBuf>,
 
-    /// The path to the Clang executable to run Clang-based tests with. If
-    /// `None` then these tests will be ignored.
+    /// The path to the **target** `clang` executable to run `clang`-based tests with. If `None`,
+    /// then these tests will be ignored.
     pub run_clang_based_tests_with: Option<String>,
 
-    /// The directory containing the sources.
+    /// Path to the directory containing the sources. This corresponds to the root folder of a
+    /// `rust-lang/rust` checkout.
+    ///
+    /// FIXME: this name is confusing, because this is actually `$checkout_root`, **not** the
+    /// `$checkout_root/src/` folder.
     pub src_root: Utf8PathBuf,
-    /// The directory containing the test suite sources. Must be a subdirectory of `src_root`.
+
+    /// Path to the directory containing the test suites sources. This corresponds to the
+    /// `$src_root/tests/` folder.
+    ///
+    /// Must be an immediate subdirectory of [`Self::src_root`].
+    ///
+    /// FIXME: this name is also confusing, maybe just call it `tests_root`.
     pub src_test_suite_root: Utf8PathBuf,
 
-    /// Root build directory (e.g. `build/`).
+    /// Path to the build directory (e.g. `build/`).
     pub build_root: Utf8PathBuf,
-    /// Test suite specific build directory (e.g. `build/host/test/ui/`).
+
+    /// Path to the test suite specific build directory (e.g. `build/host/test/ui/`).
+    ///
+    /// Must be a subdirectory of [`Self::build_root`].
     pub build_test_suite_root: Utf8PathBuf,
 
-    /// The directory containing the compiler sysroot
+    /// Path to the directory containing the sysroot of the `rustc`-under-test.
+    ///
+    /// When stage 0 is forced, this will correspond to the sysroot *of* that specified stage 0
+    /// `rustc`.
+    ///
+    /// FIXME: this name is confusing, because it doesn't specify *which* compiler this sysroot
+    /// corresponds to. It's actually the `rustc`-under-test, and not the bootstrap `rustc`, unless
+    /// stage 0 is forced and no custom stage 0 `rustc` was otherwise specified (so that it
+    /// *happens* to run against the bootstrap `rustc`, but this non-custom bootstrap `rustc` case
+    /// is not really supported).
     pub sysroot_base: Utf8PathBuf,
 
     /// The number of the stage under test.
     pub stage: u32,
+
     /// The id of the stage under test (stage1-xxx, etc).
+    ///
+    /// FIXME: reconsider this string; this is hashed for test build stamp.
     pub stage_id: String,
 
-    /// The test mode, e.g. ui or debuginfo.
+    /// The test [`Mode`]. E.g. [`Mode::Ui`]. Each test mode can correspond to one or more test
+    /// suites.
+    ///
+    /// FIXME: stop using stringly-typed test suites!
     pub mode: Mode,
 
-    /// The test suite (essentially which directory is running, but without the
-    /// directory prefix such as tests)
+    /// The test suite.
+    ///
+    /// Example: `tests/ui/` is the "UI" test *suite*, which happens to also be of the [`Mode::Ui`]
+    /// test *mode*.
+    ///
+    /// Note that the same test directory (e.g. `tests/coverage/`) may correspond to multiple test
+    /// modes, e.g. `tests/coverage/` can be run under both [`Mode::CoverageRun`] and
+    /// [`Mode::CoverageMap`].
+    ///
+    /// FIXME: stop using stringly-typed test suites!
     pub suite: String,
 
-    /// The debugger to use in debuginfo mode. Unset otherwise.
+    /// When specified, **only** the specified [`Debugger`] will be used to run against the
+    /// `tests/debuginfo` test suite. When unspecified, `compiletest` will attempt to find all three
+    /// of {`lldb`, `cdb`, `gdb`} implicitly, and then try to run the `debuginfo` test suite against
+    /// all three debuggers.
+    ///
+    /// FIXME: this implicit behavior is really nasty, in that it makes it hard for the user to
+    /// control *which* debugger(s) are available and used to run the debuginfo test suite. We
+    /// should have `bootstrap` allow the user to *explicitly* configure the debuggers, and *not*
+    /// try to implicitly discover some random debugger from the user environment. This makes the
+    /// debuginfo test suite particularly hard to work with.
     pub debugger: Option<Debugger>,
 
-    /// Run ignored tests
+    /// Run ignored tests *unconditionally*, overriding their ignore reason.
+    ///
+    /// FIXME: this is wired up through the test execution logic, but **not** accessible from
+    /// `bootstrap` directly; `compiletest` exposes this as `--ignored`. I.e. you'd have to use `./x
+    /// test $test_suite -- --ignored=true`.
     pub run_ignored: bool,
 
-    /// Whether rustc was built with debug assertions.
+    /// Whether *staged* `rustc`-under-test was built with debug assertions.
+    ///
+    /// FIXME: make it clearer that this refers to the staged `rustc`-under-test, not stage 0
+    /// `rustc`.
     pub with_rustc_debug_assertions: bool,
 
-    /// Whether std was built with debug assertions.
+    /// Whether *staged* `std` was built with debug assertions.
+    ///
+    /// FIXME: make it clearer that this refers to the staged `std`, not stage 0 `std`.
     pub with_std_debug_assertions: bool,
 
-    /// Only run tests that match these filters
+    /// Only run tests that match these filters (using `libtest` "test name contains" filter logic).
+    ///
+    /// FIXME(#139660): the current hand-rolled test executor intentionally mimics the `libtest`
+    /// "test name contains" filter matching logic to preserve previous `libtest` executor behavior,
+    /// but this is often not intuitive. We should consider changing that behavior with an MCP to do
+    /// test path *prefix* matching which better corresponds to how `compiletest` `tests/` are
+    /// organized, and how users would intuitively expect the filtering logic to work like.
     pub filters: Vec<String>,
 
-    /// Skip tests matching these substrings. Corresponds to
-    /// `test::TestOpts::skip`. `filter_exact` does not apply to these flags.
+    /// Skip tests matching these substrings. The matching logic exactly corresponds to
+    /// [`Self::filters`] but inverted.
+    ///
+    /// FIXME(#139660): ditto on test matching behavior.
     pub skip: Vec<String>,
 
-    /// Exactly match the filter, rather than a substring
+    /// Exactly match the filter, rather than a substring.
+    ///
+    /// FIXME(#139660): ditto on test matching behavior.
     pub filter_exact: bool,
 
-    /// Force the pass mode of a check/build/run-pass test to this mode.
+    /// Force the pass mode of a check/build/run test to instead use this mode instead.
+    ///
+    /// FIXME: make it even more obvious (especially in PR CI where `--pass=check` is used) when a
+    /// pass mode is forced when the test fails, because it can be very non-obvious when e.g. an
+    /// error is emitted only when `//@ build-pass` but not `//@ check-pass`.
     pub force_pass_mode: Option<PassMode>,
 
-    /// Explicitly enable or disable running.
+    /// Explicitly enable or disable running of the target test binary.
+    ///
+    /// FIXME: this scheme is a bit confusing, and at times questionable. Re-evaluate this run
+    /// scheme.
+    ///
+    /// FIXME: Currently `--run` is a tri-state, it can be `--run={auto,always,never}`, and when
+    /// `--run=auto` is specified, it's run if the platform doesn't end with `-fuchsia`. See
+    /// [`Config::run_enabled`].
     pub run: Option<bool>,
 
-    /// A command line to prefix program execution with,
-    /// for running under valgrind for example.
+    /// A command line to prefix target program execution with, for running under valgrind for
+    /// example, i.e. `$runner target.exe [args..]`. Similar to `CARGO_*_RUNNER` configuration.
     ///
-    /// Similar to `CARGO_*_RUNNER` configuration.
+    /// Note: this is not to be confused with [`Self::remote_test_client`], which is a different
+    /// scheme.
+    ///
+    /// FIXME: the runner scheme is very under-documented.
     pub runner: Option<String>,
 
-    /// Flags to pass to the compiler when building for the host
+    /// Compiler flags to pass to the *staged* `rustc`-under-test when building for the **host**
+    /// platform.
     pub host_rustcflags: Vec<String>,
 
-    /// Flags to pass to the compiler when building for the target
+    /// Compiler flags to pass to the *staged* `rustc`-under-test when building for the **target**
+    /// platform.
     pub target_rustcflags: Vec<String>,
 
-    /// Whether the compiler and stdlib has been built with randomized struct layouts
+    /// Whether the *staged* `rustc`-under-test and the associated *staged* `std` has been built
+    /// with randomized struct layouts.
     pub rust_randomized_layout: bool,
 
-    /// Whether tests should be optimized by default. Individual test-suites and test files may
-    /// override this setting.
+    /// Whether tests should be optimized by default (`-O`). Individual test suites and test files
+    /// may override this setting.
+    ///
+    /// FIXME: this flag / config option is somewhat misleading. For instance, in ui tests, it's
+    /// *only* applied to the [`PassMode::Run`] test crate and not its auxiliaries.
     pub optimize_tests: bool,
 
-    /// Target system to be tested
+    /// Target platform tuple.
     pub target: String,
 
-    /// Host triple for the compiler being invoked
+    /// Host platform tuple.
     pub host: String,
 
-    /// Path to / name of the Microsoft Console Debugger (CDB) executable
+    /// Path to / name of the Microsoft Console Debugger (CDB) executable.
+    ///
+    /// FIXME: this is an *opt-in* "override" option. When this isn't provided, we try to conjure a
+    /// cdb by looking at the user's program files on Windows... See `debuggers::find_cdb`.
     pub cdb: Option<Utf8PathBuf>,
 
-    /// Version of CDB
+    /// Version of CDB.
+    ///
+    /// FIXME: `cdb_version` is *derived* from cdb, but it's *not* technically a config!
+    ///
+    /// FIXME: audit cdb version gating.
     pub cdb_version: Option<[u16; 4]>,
 
-    /// Path to / name of the GDB executable
+    /// Path to / name of the GDB executable.
+    ///
+    /// FIXME: the fallback path when `gdb` isn't provided tries to find *a* `gdb` or `gdb.exe` from
+    /// `PATH`, which is... arguably questionable.
+    ///
+    /// FIXME: we are propagating a python from `PYTHONPATH`, not from an explicit config for gdb
+    /// debugger script.
     pub gdb: Option<String>,
 
     /// Version of GDB, encoded as ((major * 1000) + minor) * 1000 + patch
+    ///
+    /// FIXME: this gdb version gating scheme is possibly questionable -- gdb does not use semver,
+    /// only its major version is likely materially meaningful, cf.
+    /// <https://sourceware.org/gdb/wiki/Internals%20Versions>. Even the major version I'm not sure
+    /// is super meaningful. Maybe min gdb `major.minor` version gating is sufficient for the
+    /// purposes of debuginfo tests?
+    ///
+    /// FIXME: `gdb_version` is *derived* from gdb, but it's *not* technically a config!
     pub gdb_version: Option<u32>,
 
-    /// Version of LLDB
+    /// Version of LLDB.
+    ///
+    /// FIXME: `lldb_version` is *derived* from lldb, but it's *not* technically a config!
     pub lldb_version: Option<u32>,
 
-    /// Version of LLVM
+    /// Version of LLVM.
+    ///
+    /// FIXME: Audit the fallback derivation of
+    /// [`crate::directives::extract_llvm_version_from_binary`], that seems very questionable?
     pub llvm_version: Option<Version>,
 
-    /// Is LLVM a system LLVM
+    /// Is LLVM a system LLVM.
     pub system_llvm: bool,
 
-    /// Path to the android tools
+    /// Path to the android tools.
+    ///
+    /// Note: this is only used for android gdb debugger script in the debuginfo test suite.
+    ///
+    /// FIXME: take a look at this; this is piggy-backing off of gdb code paths but only for
+    /// `arm-linux-androideabi` target.
     pub android_cross_path: Utf8PathBuf,
 
-    /// Extra parameter to run adb on arm-linux-androideabi
+    /// Extra parameter to run adb on `arm-linux-androideabi`.
+    ///
+    /// FIXME: is this *only* `arm-linux-androideabi`, or is it also for other Tier 2/3 android
+    /// targets?
+    ///
+    /// FIXME: take a look at this; this is piggy-backing off of gdb code paths but only for
+    /// `arm-linux-androideabi` target.
     pub adb_path: String,
 
-    /// Extra parameter to run test suite on arm-linux-androideabi
+    /// Extra parameter to run test suite on `arm-linux-androideabi`.
+    ///
+    /// FIXME: is this *only* `arm-linux-androideabi`, or is it also for other Tier 2/3 android
+    /// targets?
+    ///
+    /// FIXME: take a look at this; this is piggy-backing off of gdb code paths but only for
+    /// `arm-linux-androideabi` target.
     pub adb_test_dir: String,
 
-    /// status whether android device available or not
+    /// Status whether android device available or not. When unavailable, this will cause tests to
+    /// panic when the test binary is attempted to be run.
+    ///
+    /// FIXME: take a look at this; this also influences adb in gdb code paths in a strange way.
     pub adb_device_status: bool,
 
-    /// the path containing LLDB's Python module
+    /// Path containing LLDB's Python module.
+    ///
+    /// FIXME: `PYTHONPATH` takes precedence over this flag...? See `runtest::run_lldb`.
     pub lldb_python_dir: Option<String>,
 
-    /// Explain what's going on
+    /// Verbose dump a lot of info.
+    ///
+    /// FIXME: this is *way* too coarse; the user can't select *which* info to verbosely dump.
     pub verbose: bool,
 
-    /// Print one character per test instead of one line
+    /// (Useless) Adjust libtest output format.
+    ///
+    /// FIXME: the hand-rolled executor does not support non-JSON output, because `compiletest` need
+    /// to package test outcome as `libtest`-esque JSON that `bootstrap` can intercept *anyway*.
+    /// However, now that we don't use the `libtest` executor, this is useless.
     pub format: OutputFormat,
 
-    /// Whether to use colors in test.
+    /// Whether to use colors in test output.
+    ///
+    /// Note: the exact control mechanism is delegated to [`colored`].
     pub color: ColorConfig,
 
-    /// where to find the remote test client process, if we're using it
+    /// Where to find the remote test client process, if we're using it.
+    ///
+    /// Note: this is *only* used for target platform executables created by `run-make` test
+    /// recipes.
+    ///
+    /// Note: this is not to be confused with [`Self::runner`], which is a different scheme.
+    ///
+    /// FIXME: the `remote_test_client` scheme is very under-documented.
     pub remote_test_client: Option<Utf8PathBuf>,
 
-    /// mode describing what file the actual ui output will be compared to
+    /// [`CompareMode`] describing what file the actual ui output will be compared to.
+    ///
+    /// FIXME: currently, [`CompareMode`] is a mishmash of lot of things (different borrow-checker
+    /// model, different trait solver, different debugger, etc.).
     pub compare_mode: Option<CompareMode>,
 
     /// If true, this will generate a coverage file with UI test files that run `MachineApplicable`
     /// diagnostics but are missing `run-rustfix` annotations. The generated coverage file is
-    /// created in `<test_suite_build_root>/rustfix_missing_coverage.txt`
+    /// created in `$test_suite_build_root/rustfix_missing_coverage.txt`
     pub rustfix_coverage: bool,
 
-    /// whether to run `tidy` (html-tidy) when a rustdoc test fails
+    /// Whether to run `tidy` (html-tidy) when a rustdoc test fails.
     pub has_html_tidy: bool,
 
-    /// whether to run `enzyme` autodiff tests
+    /// Whether to run `enzyme` autodiff tests.
     pub has_enzyme: bool,
 
-    /// The current Rust channel
+    /// The current Rust channel info.
+    ///
+    /// FIXME: treat this more carefully; "stable", "beta" and "nightly" are definitely valid, but
+    /// channel might also be "dev" or such, which should be treated as "nightly".
     pub channel: String,
 
-    /// Whether adding git commit information such as the commit hash has been enabled for building
+    /// Whether adding git commit information such as the commit hash has been enabled for building.
+    ///
+    /// FIXME: `compiletest` cannot trust `bootstrap` for this information, because `bootstrap` can
+    /// have bugs and had bugs on that logic. We need to figure out how to obtain this e.g. directly
+    /// from CI or via git locally.
     pub git_hash: bool,
 
-    /// The default Rust edition
+    /// The default Rust edition.
+    ///
+    /// FIXME: perform stronger validation for this. There are editions that *definitely* exists,
+    /// but there might also be "future" edition.
     pub edition: Option<String>,
 
-    // Configuration for various run-make tests frobbing things like C compilers
-    // or querying about various LLVM component information.
+    // Configuration for various run-make tests frobbing things like C compilers or querying about
+    // various LLVM component information.
+    //
+    // FIXME: this really should be better packaged together.
+    // FIXME: these need better docs, e.g. for *host*, or for *target*?
     pub cc: String,
     pub cxx: String,
     pub cflags: String,
@@ -381,41 +597,63 @@ pub struct Config {
     pub host_linker: Option<String>,
     pub llvm_components: String,
 
-    /// Path to a NodeJS executable. Used for JS doctests, emscripten and WASM tests
+    /// Path to a NodeJS executable. Used for JS doctests, emscripten and WASM tests.
     pub nodejs: Option<String>,
-    /// Path to a npm executable. Used for rustdoc GUI tests
+    /// Path to a npm executable. Used for rustdoc GUI tests.
     pub npm: Option<String>,
 
     /// Whether to rerun tests even if the inputs are unchanged.
     pub force_rerun: bool,
 
-    /// Only rerun the tests that result has been modified according to Git status
+    /// Only rerun the tests that result has been modified according to `git status`.
+    ///
+    /// FIXME: this is undocumented.
+    ///
+    /// FIXME: how does this interact with [`Self::force_rerun`]?
     pub only_modified: bool,
 
+    // FIXME: these are really not "config"s, but rather are information derived from
+    // `rustc`-under-test. This poses an interesting conundrum: if we're testing the
+    // `rustc`-under-test, can we trust its print request outputs and target cfgs? In theory, this
+    // itself can break or be unreliable -- ideally, we'd be sharing these kind of information not
+    // through `rustc`-under-test's execution output. In practice, however, print requests are very
+    // unlikely to completely break (we also have snapshot ui tests for them). Furthermore, even if
+    // we share them via some kind of static config, that static config can still be wrong! Who
+    // tests the tester? Therefore, we make a pragmatic compromise here, and use information derived
+    // from print requests produced by the `rustc`-under-test.
+    //
+    // FIXME: move them out from `Config`, because they are *not* configs.
     pub target_cfgs: OnceLock<TargetCfgs>,
     pub builtin_cfg_names: OnceLock<HashSet<String>>,
     pub supported_crate_types: OnceLock<HashSet<String>>,
 
+    /// FIXME: this is why we still need to depend on *staged* `std`, it's because we currently rely
+    /// on `#![feature(internal_output_capture)]` for [`std::io::set_output_capture`] to implement
+    /// `libtest`-esque `--no-capture`.
+    ///
+    /// FIXME: rename this to the more canonical `no_capture`, or better, invert this to `capture`
+    /// to avoid `!nocapture` double-negatives.
     pub nocapture: bool,
 
-    // Needed both to construct build_helper::git::GitConfig
+    /// Needed both to construct [`build_helper::git::GitConfig`].
     pub nightly_branch: String,
     pub git_merge_commit_email: String,
 
-    /// True if the profiler runtime is enabled for this target.
-    /// Used by the "needs-profiler-runtime" directive in test files.
+    /// True if the profiler runtime is enabled for this target. Used by the
+    /// `needs-profiler-runtime` directive in test files.
     pub profiler_runtime: bool,
 
     /// Command for visual diff display, e.g. `diff-tool --color=always`.
     pub diff_command: Option<String>,
 
-    /// Path to minicore aux library, used for `no_core` tests that need `core` stubs in
-    /// cross-compilation scenarios that do not otherwise want/need to `-Zbuild-std`. Used in e.g.
-    /// ABI tests.
+    /// Path to minicore aux library (`tests/auxiliary/minicore.rs`), used for `no_core` tests that
+    /// need `core` stubs in cross-compilation scenarios that do not otherwise want/need to
+    /// `-Zbuild-std`. Used in e.g. ABI tests.
     pub minicore_path: Utf8PathBuf,
 }
 
 impl Config {
+    /// FIXME: this run scheme is... confusing.
     pub fn run_enabled(&self) -> bool {
         self.run.unwrap_or_else(|| {
             // Auto-detect whether to run based on the platform.
@@ -783,11 +1021,13 @@ fn rustc_output(config: &Config, args: &[&str], envs: HashMap<String, String>) -
 
     let output = match command.output() {
         Ok(output) => output,
-        Err(e) => panic!("error: failed to run {command:?}: {e}"),
+        Err(e) => {
+            fatal!("failed to run {command:?}: {e}");
+        }
     };
     if !output.status.success() {
-        panic!(
-            "error: failed to run {command:?}\n--- stdout\n{}\n--- stderr\n{}",
+        fatal!(
+            "failed to run {command:?}\n--- stdout\n{}\n--- stderr\n{}",
             String::from_utf8(output.stdout).unwrap(),
             String::from_utf8(output.stderr).unwrap(),
         );
diff --git a/src/tools/compiletest/src/debuggers.rs b/src/tools/compiletest/src/debuggers.rs
index c133d7fd4fb..0edc3d82d4f 100644
--- a/src/tools/compiletest/src/debuggers.rs
+++ b/src/tools/compiletest/src/debuggers.rs
@@ -51,6 +51,7 @@ pub(crate) fn configure_gdb(config: &Config) -> Option<Arc<Config>> {
 pub(crate) fn configure_lldb(config: &Config) -> Option<Arc<Config>> {
     config.lldb_python_dir.as_ref()?;
 
+    // FIXME: this is super old
     if let Some(350) = config.lldb_version {
         println!(
             "WARNING: The used version of LLDB (350) has a \
@@ -78,6 +79,7 @@ fn is_pc_windows_msvc_target(target: &str) -> bool {
     target.ends_with("-pc-windows-msvc")
 }
 
+/// FIXME: this is very questionable...
 fn find_cdb(target: &str) -> Option<Utf8PathBuf> {
     if !(cfg!(windows) && is_pc_windows_msvc_target(target)) {
         return None;
diff --git a/src/tools/compiletest/src/diagnostics.rs b/src/tools/compiletest/src/diagnostics.rs
new file mode 100644
index 00000000000..207a6cb91d7
--- /dev/null
+++ b/src/tools/compiletest/src/diagnostics.rs
@@ -0,0 +1,46 @@
+//! Collection of diagnostics helpers for `compiletest` *itself*.
+
+#[macro_export]
+macro_rules! fatal {
+    ($($arg:tt)*) => {
+        let status = ::colored::Colorize::bright_red("FATAL: ");
+        let status = ::colored::Colorize::bold(status);
+        eprint!("{status}");
+        eprintln!($($arg)*);
+        // This intentionally uses a seemingly-redundant panic to include backtrace location.
+        //
+        // FIXME: in the long term, we should handle "logic bug in compiletest itself" vs "fatal
+        // user error" separately.
+        panic!("fatal error");
+    };
+}
+
+#[macro_export]
+macro_rules! error {
+    ($($arg:tt)*) => {
+        let status = ::colored::Colorize::red("ERROR: ");
+        let status = ::colored::Colorize::bold(status);
+        eprint!("{status}");
+        eprintln!($($arg)*);
+    };
+}
+
+#[macro_export]
+macro_rules! warning {
+    ($($arg:tt)*) => {
+        let status = ::colored::Colorize::yellow("WARNING: ");
+        let status = ::colored::Colorize::bold(status);
+        eprint!("{status}");
+        eprintln!($($arg)*);
+    };
+}
+
+#[macro_export]
+macro_rules! help {
+    ($($arg:tt)*) => {
+        let status = ::colored::Colorize::cyan("HELP: ");
+        let status = ::colored::Colorize::bold(status);
+        eprint!("{status}");
+        eprintln!($($arg)*);
+    };
+}
diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs
index 2ecb4fc8652..adf2a7bffef 100644
--- a/src/tools/compiletest/src/directive-list.rs
+++ b/src/tools/compiletest/src/directive-list.rs
@@ -1,6 +1,6 @@
 /// This was originally generated by collecting directives from ui tests and then extracting their
 /// directive names. This is **not** an exhaustive list of all possible directives. Instead, this is
-/// a best-effort approximation for diagnostics. Add new headers to this list when needed.
+/// a best-effort approximation for diagnostics. Add new directives to this list when needed.
 const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     // tidy-alphabetical-start
     "add-core-stubs",
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/directives.rs
index 2b203bb309c..a6242cf0c22 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/directives.rs
@@ -11,10 +11,11 @@ use tracing::*;
 
 use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
 use crate::debuggers::{extract_cdb_version, extract_gdb_version};
+use crate::directives::auxiliary::{AuxProps, parse_and_update_aux};
+use crate::directives::needs::CachedNeedsConditions;
 use crate::errors::ErrorKind;
 use crate::executor::{CollectedTestDesc, ShouldPanic};
-use crate::header::auxiliary::{AuxProps, parse_and_update_aux};
-use crate::header::needs::CachedNeedsConditions;
+use crate::help;
 use crate::util::static_regex;
 
 pub(crate) mod auxiliary;
@@ -23,11 +24,11 @@ mod needs;
 #[cfg(test)]
 mod tests;
 
-pub struct HeadersCache {
+pub struct DirectivesCache {
     needs: CachedNeedsConditions,
 }
 
-impl HeadersCache {
+impl DirectivesCache {
     pub fn load(config: &Config) -> Self {
         Self { needs: CachedNeedsConditions::load(config) }
     }
@@ -53,7 +54,7 @@ impl EarlyProps {
     pub fn from_reader<R: Read>(config: &Config, testfile: &Utf8Path, rdr: R) -> Self {
         let mut props = EarlyProps::default();
         let mut poisoned = false;
-        iter_header(
+        iter_directives(
             config.mode,
             &config.suite,
             &mut poisoned,
@@ -137,12 +138,12 @@ pub struct TestProps {
     pub incremental_dir: Option<Utf8PathBuf>,
     // If `true`, this test will use incremental compilation.
     //
-    // This can be set manually with the `incremental` header, or implicitly
+    // This can be set manually with the `incremental` directive, or implicitly
     // by being a part of an incremental mode test. Using the `incremental`
-    // header should be avoided if possible; using an incremental mode test is
+    // directive should be avoided if possible; using an incremental mode test is
     // preferred. Incremental mode tests support multiple passes, which can
     // verify that the incremental cache can be loaded properly after being
-    // created. Just setting the header will only verify the behavior with
+    // created. Just setting the directive will only verify the behavior with
     // creating an incremental cache, but doesn't check that it is created
     // correctly.
     //
@@ -346,7 +347,7 @@ impl TestProps {
 
             let mut poisoned = false;
 
-            iter_header(
+            iter_directives(
                 config.mode,
                 &config.suite,
                 &mut poisoned,
@@ -641,11 +642,11 @@ impl TestProps {
         let check_ui = |mode: &str| {
             // Mode::Crashes may need build-fail in order to trigger llvm errors or stack overflows
             if config.mode != Mode::Ui && config.mode != Mode::Crashes {
-                panic!("`{}-fail` header is only supported in UI tests", mode);
+                panic!("`{}-fail` directive is only supported in UI tests", mode);
             }
         };
         if config.mode == Mode::Ui && config.parse_name_directive(ln, "compile-fail") {
-            panic!("`compile-fail` header is useless in UI tests");
+            panic!("`compile-fail` directive is useless in UI tests");
         }
         let fail_mode = if config.parse_name_directive(ln, "check-fail") {
             check_ui("check");
@@ -661,7 +662,7 @@ impl TestProps {
         };
         match (self.fail_mode, fail_mode) {
             (None, Some(_)) => self.fail_mode = fail_mode,
-            (Some(_), Some(_)) => panic!("multiple `*-fail` headers in a single test"),
+            (Some(_), Some(_)) => panic!("multiple `*-fail` directives in a single test"),
             (_, None) => {}
         }
     }
@@ -673,10 +674,10 @@ impl TestProps {
             (Mode::Codegen, "build-pass") => (),
             (Mode::Incremental, _) => {
                 if revision.is_some() && !self.revisions.iter().all(|r| r.starts_with("cfail")) {
-                    panic!("`{s}` header is only supported in `cfail` incremental tests")
+                    panic!("`{s}` directive is only supported in `cfail` incremental tests")
                 }
             }
-            (mode, _) => panic!("`{s}` header is not supported in `{mode}` tests"),
+            (mode, _) => panic!("`{s}` directive is not supported in `{mode}` tests"),
         };
         let pass_mode = if config.parse_name_directive(ln, "check-pass") {
             check_no_run("check-pass");
@@ -692,7 +693,7 @@ impl TestProps {
         };
         match (self.pass_mode, pass_mode) {
             (None, Some(_)) => self.pass_mode = pass_mode,
-            (Some(_), Some(_)) => panic!("multiple `*-pass` headers in a single test"),
+            (Some(_), Some(_)) => panic!("multiple `*-pass` directives in a single test"),
             (_, None) => {}
         }
     }
@@ -793,7 +794,7 @@ const KNOWN_JSONDOCCK_DIRECTIVE_NAMES: &[&str] =
     &["count", "!count", "has", "!has", "is", "!is", "ismany", "!ismany", "set", "!set"];
 
 /// The (partly) broken-down contents of a line containing a test directive,
-/// which [`iter_header`] passes to its callback function.
+/// which [`iter_directives`] passes to its callback function.
 ///
 /// For example:
 ///
@@ -866,7 +867,7 @@ pub(crate) fn check_directive<'a>(
 
 const COMPILETEST_DIRECTIVE_PREFIX: &str = "//@";
 
-fn iter_header(
+fn iter_directives(
     mode: Mode,
     _suite: &str,
     poisoned: &mut bool,
@@ -920,9 +921,9 @@ fn iter_header(
             if !is_known_directive {
                 *poisoned = true;
 
-                eprintln!(
-                    "error: detected unknown compiletest test directive `{}` in {}:{}",
-                    directive_line.raw_directive, testfile, line_number,
+                error!(
+                    "{testfile}:{line_number}: detected unknown compiletest test directive `{}`",
+                    directive_line.raw_directive,
                 );
 
                 return;
@@ -931,11 +932,11 @@ fn iter_header(
             if let Some(trailing_directive) = &trailing_directive {
                 *poisoned = true;
 
-                eprintln!(
-                    "error: detected trailing compiletest test directive `{}` in {}:{}\n \
-                      help: put the trailing directive in it's own line: `//@ {}`",
-                    trailing_directive, testfile, line_number, trailing_directive,
+                error!(
+                    "{testfile}:{line_number}: detected trailing compiletest test directive `{}`",
+                    trailing_directive,
                 );
+                help!("put the trailing directive in it's own line: `//@ {}`", trailing_directive);
 
                 return;
             }
@@ -1031,10 +1032,9 @@ impl Config {
         };
 
         let Some((regex, replacement)) = parse_normalize_rule(raw_value) else {
-            panic!(
-                "couldn't parse custom normalization rule: `{raw_directive}`\n\
-                help: expected syntax is: `{directive_name}: \"REGEX\" -> \"REPLACEMENT\"`"
-            );
+            error!("couldn't parse custom normalization rule: `{raw_directive}`");
+            help!("expected syntax is: `{directive_name}: \"REGEX\" -> \"REPLACEMENT\"`");
+            panic!("invalid normalization rule detected");
         };
         Some(NormalizeRule { kind, regex, replacement })
     }
@@ -1163,8 +1163,7 @@ enum NormalizeKind {
     Stderr64bit,
 }
 
-/// Parses the regex and replacement values of a `//@ normalize-*` header,
-/// in the format:
+/// Parses the regex and replacement values of a `//@ normalize-*` directive, in the format:
 /// ```text
 /// "REGEX" -> "REPLACEMENT"
 /// ```
@@ -1373,7 +1372,7 @@ where
 
 pub(crate) fn make_test_description<R: Read>(
     config: &Config,
-    cache: &HeadersCache,
+    cache: &DirectivesCache,
     name: String,
     path: &Utf8Path,
     src: R,
@@ -1387,7 +1386,7 @@ pub(crate) fn make_test_description<R: Read>(
     let mut local_poisoned = false;
 
     // Scan through the test file to handle `ignore-*`, `only-*`, and `needs-*` directives.
-    iter_header(
+    iter_directives(
         config.mode,
         &config.suite,
         &mut local_poisoned,
@@ -1406,7 +1405,7 @@ pub(crate) fn make_test_description<R: Read>(
                             ignore_message = Some(reason.into());
                         }
                         IgnoreDecision::Error { message } => {
-                            eprintln!("error: {}:{line_number}: {message}", path);
+                            error!("{path}:{line_number}: {message}");
                             *poisoned = true;
                             return;
                         }
diff --git a/src/tools/compiletest/src/header/auxiliary.rs b/src/tools/compiletest/src/directives/auxiliary.rs
index 0e1f3a785f8..cdb75f6ffa9 100644
--- a/src/tools/compiletest/src/header/auxiliary.rs
+++ b/src/tools/compiletest/src/directives/auxiliary.rs
@@ -3,8 +3,8 @@
 
 use std::iter;
 
+use super::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO};
 use crate::common::Config;
-use crate::header::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO};
 
 /// Properties parsed from `aux-*` test directives.
 #[derive(Clone, Debug, Default)]
diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/directives/cfg.rs
index f1f1384afb9..35f6a9e1644 100644
--- a/src/tools/compiletest/src/header/cfg.rs
+++ b/src/tools/compiletest/src/directives/cfg.rs
@@ -1,7 +1,7 @@
 use std::collections::HashSet;
 
 use crate::common::{CompareMode, Config, Debugger};
-use crate::header::IgnoreDecision;
+use crate::directives::IgnoreDecision;
 
 const EXTRA_ARCHS: &[&str] = &["spirv"];
 
diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/directives/needs.rs
index b1165f4bb18..ee46f4c70cb 100644
--- a/src/tools/compiletest/src/header/needs.rs
+++ b/src/tools/compiletest/src/directives/needs.rs
@@ -1,5 +1,5 @@
 use crate::common::{Config, KNOWN_CRATE_TYPES, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer};
-use crate::header::{IgnoreDecision, llvm_has_libzstd};
+use crate::directives::{IgnoreDecision, llvm_has_libzstd};
 
 pub(super) fn handle_needs(
     cache: &CachedNeedsConditions,
diff --git a/src/tools/compiletest/src/header/test-auxillary/error_annotation.rs b/src/tools/compiletest/src/directives/test-auxillary/error_annotation.rs
index fea66a5e07b..fea66a5e07b 100644
--- a/src/tools/compiletest/src/header/test-auxillary/error_annotation.rs
+++ b/src/tools/compiletest/src/directives/test-auxillary/error_annotation.rs
diff --git a/src/tools/compiletest/src/header/test-auxillary/known_directive.rs b/src/tools/compiletest/src/directives/test-auxillary/known_directive.rs
index 99834b14c1e..99834b14c1e 100644
--- a/src/tools/compiletest/src/header/test-auxillary/known_directive.rs
+++ b/src/tools/compiletest/src/directives/test-auxillary/known_directive.rs
diff --git a/src/tools/compiletest/src/header/test-auxillary/not_rs.Makefile b/src/tools/compiletest/src/directives/test-auxillary/not_rs.Makefile
index 4b565e0e6df..4b565e0e6df 100644
--- a/src/tools/compiletest/src/header/test-auxillary/not_rs.Makefile
+++ b/src/tools/compiletest/src/directives/test-auxillary/not_rs.Makefile
diff --git a/src/tools/compiletest/src/header/test-auxillary/unknown_directive.rs b/src/tools/compiletest/src/directives/test-auxillary/unknown_directive.rs
index d4406031043..d4406031043 100644
--- a/src/tools/compiletest/src/header/test-auxillary/unknown_directive.rs
+++ b/src/tools/compiletest/src/directives/test-auxillary/unknown_directive.rs
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/directives/tests.rs
index 31b49b09bcd..d4570f82677 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/directives/tests.rs
@@ -4,7 +4,7 @@ use camino::Utf8Path;
 use semver::Version;
 
 use super::{
-    EarlyProps, HeadersCache, extract_llvm_version, extract_version_range, iter_header,
+    DirectivesCache, EarlyProps, extract_llvm_version, extract_version_range, iter_directives,
     parse_normalize_rule,
 };
 use crate::common::{Config, Debugger, Mode};
@@ -17,9 +17,9 @@ fn make_test_description<R: Read>(
     src: R,
     revision: Option<&str>,
 ) -> CollectedTestDesc {
-    let cache = HeadersCache::load(config);
+    let cache = DirectivesCache::load(config);
     let mut poisoned = false;
-    let test = crate::header::make_test_description(
+    let test = crate::directives::make_test_description(
         config,
         &cache,
         name,
@@ -785,7 +785,7 @@ fn threads_support() {
 
 fn run_path(poisoned: &mut bool, path: &Utf8Path, buf: &[u8]) {
     let rdr = std::io::Cursor::new(&buf);
-    iter_header(Mode::Ui, "ui", poisoned, path, rdr, &mut |_| {});
+    iter_directives(Mode::Ui, "ui", poisoned, path, rdr, &mut |_| {});
 }
 
 #[test]
diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs
index 0c4ef36828a..df64f12784f 100644
--- a/src/tools/compiletest/src/executor.rs
+++ b/src/tools/compiletest/src/executor.rs
@@ -207,9 +207,9 @@ impl TestOutcome {
 ///
 /// Adapted from `filter_tests` in libtest.
 ///
-/// FIXME(#139660): After the libtest dependency is removed, redesign the whole
-/// filtering system to do a better job of understanding and filtering _paths_,
-/// instead of being tied to libtest's substring/exact matching behaviour.
+/// FIXME(#139660): After the libtest dependency is removed, redesign the whole filtering system to
+/// do a better job of understanding and filtering _paths_, instead of being tied to libtest's
+/// substring/exact matching behaviour.
 fn filter_tests(opts: &Config, tests: Vec<CollectedTest>) -> Vec<CollectedTest> {
     let mut filtered = tests;
 
@@ -235,9 +235,9 @@ fn filter_tests(opts: &Config, tests: Vec<CollectedTest>) -> Vec<CollectedTest>
 ///
 /// Copied from `get_concurrency` in libtest.
 ///
-/// FIXME(#139660): After the libtest dependency is removed, consider making
-/// bootstrap specify the number of threads on the command-line, instead of
-/// propagating the `RUST_TEST_THREADS` environment variable.
+/// FIXME(#139660): After the libtest dependency is removed, consider making bootstrap specify the
+/// number of threads on the command-line, instead of propagating the `RUST_TEST_THREADS`
+/// environment variable.
 fn get_concurrency() -> usize {
     if let Ok(value) = env::var("RUST_TEST_THREADS") {
         match value.parse::<NonZero<usize>>().ok() {
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index 0db4d3f6a41..9819079e284 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -11,9 +11,10 @@ mod tests;
 pub mod common;
 pub mod compute_diff;
 mod debuggers;
+pub mod diagnostics;
+pub mod directives;
 pub mod errors;
 mod executor;
-pub mod header;
 mod json;
 mod raise_fd_limit;
 mod read2;
@@ -33,16 +34,16 @@ use build_helper::git::{get_git_modified_files, get_git_untracked_files};
 use camino::{Utf8Path, Utf8PathBuf};
 use getopts::Options;
 use rayon::iter::{ParallelBridge, ParallelIterator};
-use tracing::*;
+use tracing::debug;
 use walkdir::WalkDir;
 
-use self::header::{EarlyProps, make_test_description};
+use self::directives::{EarlyProps, make_test_description};
 use crate::common::{
     CompareMode, Config, Debugger, Mode, PassMode, TestPaths, UI_EXTENSIONS, expected_output_path,
     output_base_dir, output_relative_path,
 };
+use crate::directives::DirectivesCache;
 use crate::executor::{CollectedTest, ColorConfig, OutputFormat};
-use crate::header::HeadersCache;
 use crate::util::logv;
 
 /// Creates the `Config` instance for this invocation of compiletest.
@@ -51,12 +52,6 @@ use crate::util::logv;
 /// some code here that inspects environment variables or even runs executables
 /// (e.g. when discovering debugger versions).
 pub fn parse_config(args: Vec<String>) -> Config {
-    if env::var("RUST_TEST_NOCAPTURE").is_ok() {
-        eprintln!(
-            "WARNING: RUST_TEST_NOCAPTURE is not supported. Use the `--no-capture` flag instead."
-        );
-    }
-
     let mut opts = Options::new();
     opts.reqopt("", "compile-lib-path", "path to host shared libraries", "PATH")
         .reqopt("", "run-lib-path", "path to target shared libraries", "PATH")
@@ -247,9 +242,12 @@ pub fn parse_config(args: Vec<String>) -> Config {
 
     let target = opt_str2(matches.opt_str("target"));
     let android_cross_path = opt_path(matches, "android-cross-path");
+    // FIXME: `cdb_version` is *derived* from cdb, but it's *not* technically a config!
     let (cdb, cdb_version) = debuggers::analyze_cdb(matches.opt_str("cdb"), &target);
+    // FIXME: `gdb_version` is *derived* from gdb, but it's *not* technically a config!
     let (gdb, gdb_version) =
         debuggers::analyze_gdb(matches.opt_str("gdb"), &target, &android_cross_path);
+    // FIXME: `lldb_version` is *derived* from lldb, but it's *not* technically a config!
     let lldb_version =
         matches.opt_str("lldb-version").as_deref().and_then(debuggers::extract_lldb_version);
     let color = match matches.opt_str("color").as_deref() {
@@ -258,9 +256,12 @@ pub fn parse_config(args: Vec<String>) -> Config {
         Some("never") => ColorConfig::NeverColor,
         Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x),
     };
+    // FIXME: this is very questionable, we really should be obtaining LLVM version info from
+    // `bootstrap`, and not trying to be figuring out that in `compiletest` by running the
+    // `FileCheck` binary.
     let llvm_version =
-        matches.opt_str("llvm-version").as_deref().map(header::extract_llvm_version).or_else(
-            || header::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?),
+        matches.opt_str("llvm-version").as_deref().map(directives::extract_llvm_version).or_else(
+            || directives::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?),
         );
 
     let run_ignored = matches.opt_present("ignored");
@@ -375,6 +376,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
             mode.parse::<PassMode>()
                 .unwrap_or_else(|_| panic!("unknown `--pass` option `{}` given", mode))
         }),
+        // FIXME: this run scheme is... confusing.
         run: matches.opt_str("run").and_then(|mode| match mode.as_str() {
             "auto" => None,
             "always" => Some(true),
@@ -550,6 +552,10 @@ pub fn run_tests(config: Arc<Config>) {
                 Some(Debugger::Cdb) => configs.extend(debuggers::configure_cdb(&config)),
                 Some(Debugger::Gdb) => configs.extend(debuggers::configure_gdb(&config)),
                 Some(Debugger::Lldb) => configs.extend(debuggers::configure_lldb(&config)),
+                // FIXME: the *implicit* debugger discovery makes it really difficult to control
+                // which {`cdb`, `gdb`, `lldb`} are used. These should **not** be implicitly
+                // discovered by `compiletest`; these should be explicit `bootstrap` configuration
+                // options that are passed to `compiletest`!
                 None => {
                     configs.extend(debuggers::configure_cdb(&config));
                     configs.extend(debuggers::configure_gdb(&config));
@@ -623,7 +629,7 @@ pub fn run_tests(config: Arc<Config>) {
 /// Read-only context data used during test collection.
 struct TestCollectorCx {
     config: Arc<Config>,
-    cache: HeadersCache,
+    cache: DirectivesCache,
     common_inputs_stamp: Stamp,
     modified_tests: Vec<Utf8PathBuf>,
 }
@@ -657,12 +663,9 @@ pub(crate) fn collect_and_make_tests(config: Arc<Config>) -> Vec<CollectedTest>
     let common_inputs_stamp = common_inputs_stamp(&config);
     let modified_tests =
         modified_tests(&config, &config.src_test_suite_root).unwrap_or_else(|err| {
-            panic!(
-                "modified_tests got error from dir: {}, error: {}",
-                config.src_test_suite_root, err
-            )
+            fatal!("modified_tests: {}: {err}", config.src_test_suite_root);
         });
-    let cache = HeadersCache::load(&config);
+    let cache = DirectivesCache::load(&config);
 
     let cx = TestCollectorCx { config, cache, common_inputs_stamp, modified_tests };
     let collector = collect_tests_from_dir(&cx, &cx.config.src_test_suite_root, Utf8Path::new(""))
@@ -1111,3 +1114,20 @@ fn check_for_overlapping_test_paths(found_path_stems: &HashSet<Utf8PathBuf>) {
         );
     }
 }
+
+pub fn early_config_check(config: &Config) {
+    if !config.has_html_tidy && config.mode == Mode::Rustdoc {
+        warning!("`tidy` (html-tidy.org) is not installed; diffs will not be generated");
+    }
+
+    if !config.profiler_runtime && config.mode == Mode::CoverageRun {
+        let actioned = if config.bless { "blessed" } else { "checked" };
+        warning!("profiler runtime is not available, so `.coverage` files won't be {actioned}");
+        help!("try setting `profiler = true` in the `[build]` section of `bootstrap.toml`");
+    }
+
+    // `RUST_TEST_NOCAPTURE` is a libtest env var, but we don't callout to libtest.
+    if env::var("RUST_TEST_NOCAPTURE").is_ok() {
+        warning!("`RUST_TEST_NOCAPTURE` is not supported; use the `--no-capture` flag instead");
+    }
+}
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
deleted file mode 100644
index b9ae583581e..00000000000
--- a/src/tools/compiletest/src/main.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-use std::env;
-use std::io::IsTerminal;
-use std::sync::Arc;
-
-use compiletest::common::Mode;
-use compiletest::{log_config, parse_config, run_tests};
-
-fn main() {
-    tracing_subscriber::fmt::init();
-
-    // colored checks stdout by default, but for some reason only stderr is a terminal.
-    // compiletest *does* print many things to stdout, but it doesn't really matter.
-    if std::io::stderr().is_terminal()
-        && matches!(std::env::var("NO_COLOR").as_deref(), Err(_) | Ok("0"))
-    {
-        colored::control::set_override(true);
-    }
-
-    let config = Arc::new(parse_config(env::args().collect()));
-
-    if !config.has_html_tidy && config.mode == Mode::Rustdoc {
-        eprintln!("warning: `tidy` (html-tidy.org) is not installed; diffs will not be generated");
-    }
-
-    if !config.profiler_runtime && config.mode == Mode::CoverageRun {
-        let actioned = if config.bless { "blessed" } else { "checked" };
-        eprintln!(
-            r#"
-WARNING: profiler runtime is not available, so `.coverage` files won't be {actioned}
-help: try setting `profiler = true` in the `[build]` section of `bootstrap.toml`"#
-        );
-    }
-
-    log_config(&config);
-    run_tests(config);
-}
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 980e89889ab..3e879e0e4bb 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -23,11 +23,11 @@ use crate::common::{
     output_base_dir, output_base_name, output_testname_unique,
 };
 use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff};
+use crate::directives::TestProps;
 use crate::errors::{Error, ErrorKind, load_errors};
-use crate::header::TestProps;
 use crate::read2::{Truncated, read2_abbreviated};
 use crate::util::{Utf8PathBufExt, add_dylib_path, logv, static_regex};
-use crate::{ColorConfig, json, stamp_file_path};
+use crate::{ColorConfig, help, json, stamp_file_path, warning};
 
 mod debugger;
 
@@ -121,6 +121,8 @@ pub fn run(config: Arc<Config>, testpaths: &TestPaths, revision: Option<&str>) {
         }
 
         _ => {
+            // FIXME: this logic seems strange as well.
+
             // android has its own gdb handling
             if config.debugger == Some(Debugger::Gdb) && config.gdb.is_none() {
                 panic!("gdb not available but debuginfo gdb debuginfo test requested");
@@ -485,12 +487,15 @@ impl<'test> TestCx<'test> {
                 .windows(2)
                 .any(|args| args == cfg_arg || args[0] == arg || args[1] == arg)
             {
-                panic!(
-                    "error: redundant cfg argument `{normalized_revision}` is already created by the revision"
+                error!(
+                    "redundant cfg argument `{normalized_revision}` is already created by the \
+                    revision"
                 );
+                panic!("redundant cfg argument");
             }
             if self.config.builtin_cfg_names().contains(&normalized_revision) {
-                panic!("error: revision `{normalized_revision}` collides with a builtin cfg");
+                error!("revision `{normalized_revision}` collides with a built-in cfg");
+                panic!("revision collides with built-in cfg");
             }
             cmd.args(cfg_arg);
         }
@@ -1052,18 +1057,20 @@ impl<'test> TestCx<'test> {
         let proc_res = match &*self.config.target {
             // This is pretty similar to below, we're transforming:
             //
-            //      program arg1 arg2
+            // ```text
+            // program arg1 arg2
+            // ```
             //
             // into
             //
-            //      remote-test-client run program 2 support-lib.so support-lib2.so arg1 arg2
+            // ```text
+            // remote-test-client run program 2 support-lib.so support-lib2.so arg1 arg2
+            // ```
             //
-            // The test-client program will upload `program` to the emulator
-            // along with all other support libraries listed (in this case
-            // `support-lib.so` and `support-lib2.so`. It will then execute
-            // the program on the emulator with the arguments specified
-            // (in the environment we give the process) and then report back
-            // the same result.
+            // The test-client program will upload `program` to the emulator along with all other
+            // support libraries listed (in this case `support-lib.so` and `support-lib2.so`. It
+            // will then execute the program on the emulator with the arguments specified (in the
+            // environment we give the process) and then report back the same result.
             _ if self.config.remote_test_client.is_some() => {
                 let aux_dir = self.aux_output_dir_name();
                 let ProcArgs { prog, args } = self.make_run_args();
@@ -1529,6 +1536,8 @@ impl<'test> TestCx<'test> {
         ));
 
         // Optionally prevent default --sysroot if specified in test compile-flags.
+        //
+        // FIXME: I feel like this logic is fairly sus.
         if !self.props.compile_flags.iter().any(|flag| flag.starts_with("--sysroot"))
             && !self.config.host_rustcflags.iter().any(|flag| flag == "--sysroot")
         {
@@ -1915,7 +1924,8 @@ impl<'test> TestCx<'test> {
 
     fn dump_output_file(&self, out: &str, extension: &str) {
         let outfile = self.make_out_name(extension);
-        fs::write(outfile.as_std_path(), out).unwrap();
+        fs::write(outfile.as_std_path(), out)
+            .unwrap_or_else(|err| panic!("failed to write {outfile}: {err:?}"));
     }
 
     /// Creates a filename for output with the given extension.
@@ -2036,7 +2046,7 @@ impl<'test> TestCx<'test> {
         // Provide more context on failures.
         filecheck.args(&["--dump-input-context", "100"]);
 
-        // Add custom flags supplied by the `filecheck-flags:` test header.
+        // Add custom flags supplied by the `filecheck-flags:` test directive.
         filecheck.args(&self.props.filecheck_flags);
 
         // FIXME(jieyouxu): don't pass an empty Path
@@ -2167,9 +2177,10 @@ impl<'test> TestCx<'test> {
             println!("{}", String::from_utf8_lossy(&output.stdout));
             eprintln!("{}", String::from_utf8_lossy(&output.stderr));
         } else {
-            eprintln!("warning: no pager configured, falling back to unified diff");
-            eprintln!(
-                "help: try configuring a git pager (e.g. `delta`) with `git config --global core.pager delta`"
+            warning!("no pager configured, falling back to unified diff");
+            help!(
+                "try configuring a git pager (e.g. `delta`) with \
+                `git config --global core.pager delta`"
             );
             let mut out = io::stdout();
             let mut diff = BufReader::new(File::open(&diff_filename).unwrap());
diff --git a/src/tools/compiletest/src/runtest/codegen_units.rs b/src/tools/compiletest/src/runtest/codegen_units.rs
index 8dfa8d18d1a..44ddcb1d288 100644
--- a/src/tools/compiletest/src/runtest/codegen_units.rs
+++ b/src/tools/compiletest/src/runtest/codegen_units.rs
@@ -1,8 +1,8 @@
 use std::collections::HashSet;
 
 use super::{Emit, TestCx, WillExecute};
-use crate::errors;
 use crate::util::static_regex;
+use crate::{errors, fatal};
 
 impl TestCx<'_> {
     pub(super) fn run_codegen_units_test(&self) {
@@ -100,7 +100,7 @@ impl TestCx<'_> {
         }
 
         if !(missing.is_empty() && unexpected.is_empty() && wrong_cgus.is_empty()) {
-            panic!();
+            fatal!("!(missing.is_empty() && unexpected.is_empty() && wrong_cgus.is_empty())");
         }
 
         #[derive(Clone, Eq, PartialEq)]
diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs
index 31240dff9a1..471e4a4c819 100644
--- a/src/tools/compiletest/src/runtest/debuginfo.rs
+++ b/src/tools/compiletest/src/runtest/debuginfo.rs
@@ -49,7 +49,7 @@ impl TestCx<'_> {
             std::fs::remove_file(pdb_file).unwrap();
         }
 
-        // compile test file (it should have 'compile-flags:-g' in the header)
+        // compile test file (it should have 'compile-flags:-g' in the directive)
         let should_run = self.run_if_enabled();
         let compile_result = self.compile_test(should_run, Emit::None);
         if !compile_result.status.success() {
@@ -135,7 +135,7 @@ impl TestCx<'_> {
             .unwrap_or_else(|e| self.fatal(&e));
         let mut cmds = dbg_cmds.commands.join("\n");
 
-        // compile test file (it should have 'compile-flags:-g' in the header)
+        // compile test file (it should have 'compile-flags:-g' in the directive)
         let should_run = self.run_if_enabled();
         let compiler_run_result = self.compile_test(should_run, Emit::None);
         if !compiler_run_result.status.success() {
@@ -322,6 +322,8 @@ impl TestCx<'_> {
                 &["-quiet".as_ref(), "-batch".as_ref(), "-nx".as_ref(), &debugger_script];
 
             let mut gdb = Command::new(self.config.gdb.as_ref().unwrap());
+
+            // FIXME: we are propagating `PYTHONPATH` from the environment, not a compiletest flag!
             let pythonpath = if let Ok(pp) = std::env::var("PYTHONPATH") {
                 format!("{pp}:{rust_pp_module_abs_path}")
             } else {
@@ -359,7 +361,7 @@ impl TestCx<'_> {
     }
 
     fn run_debuginfo_lldb_test_no_opt(&self) {
-        // compile test file (it should have 'compile-flags:-g' in the header)
+        // compile test file (it should have 'compile-flags:-g' in the directive)
         let should_run = self.run_if_enabled();
         let compile_result = self.compile_test(should_run, Emit::None);
         if !compile_result.status.success() {
@@ -443,6 +445,8 @@ impl TestCx<'_> {
     fn run_lldb(&self, test_executable: &Utf8Path, debugger_script: &Utf8Path) -> ProcRes {
         // Prepare the lldb_batchmode which executes the debugger script
         let lldb_script_path = self.config.src_root.join("src/etc/lldb_batchmode.py");
+
+        // FIXME: `PYTHONPATH` takes precedence over the flag...?
         let pythonpath = if let Ok(pp) = std::env::var("PYTHONPATH") {
             format!("{pp}:{}", self.config.lldb_python_dir.as_ref().unwrap())
         } else {
diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs
index cc50a918f75..f6bc85cd051 100644
--- a/src/tools/compiletest/src/runtest/ui.rs
+++ b/src/tools/compiletest/src/runtest/ui.rs
@@ -52,10 +52,10 @@ impl TestCx<'_> {
             // don't test rustfix with nll right now
         } else if self.config.rustfix_coverage {
             // Find out which tests have `MachineApplicable` suggestions but are missing
-            // `run-rustfix` or `run-rustfix-only-machine-applicable` headers.
+            // `run-rustfix` or `run-rustfix-only-machine-applicable` directives.
             //
             // This will return an empty `Vec` in case the executed test file has a
-            // `compile-flags: --error-format=xxxx` header with a value other than `json`.
+            // `compile-flags: --error-format=xxxx` directive with a value other than `json`.
             let suggestions = get_suggestions_from_json(
                 &rustfix_input,
                 &HashSet::new(),
diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml
index 9dbf51e9796..11c0f08debe 100644
--- a/src/tools/miri/.github/workflows/ci.yml
+++ b/src/tools/miri/.github/workflows/ci.yml
@@ -13,35 +13,82 @@ defaults:
     shell: bash
 
 jobs:
-  build:
+  test:
+    name: test (${{ matrix.host_target }})
     strategy:
       fail-fast: false
       matrix:
         include:
-          - os: ubuntu-latest
-            host_target: x86_64-unknown-linux-gnu
-          - os: macos-14
-            host_target: aarch64-apple-darwin
-          - os: windows-latest
-            host_target: i686-pc-windows-msvc
+          - host_target: x86_64-unknown-linux-gnu
+            os: ubuntu-latest
+          - host_target: i686-unknown-linux-gnu
+            os: ubuntu-latest
+            multiarch: i386
+            gcc_cross: i686-linux-gnu
+          - host_target: aarch64-unknown-linux-gnu
+            os: ubuntu-24.04-arm
+          - host_target: armv7-unknown-linux-gnueabihf
+            os: ubuntu-24.04-arm
+            multiarch: armhf
+            gcc_cross: arm-linux-gnueabihf
+          - host_target: riscv64gc-unknown-linux-gnu
+            os: ubuntu-latest
+            multiarch: riscv64
+            gcc_cross: riscv64-linux-gnu
+            qemu: true
+          - host_target: s390x-unknown-linux-gnu
+            os: ubuntu-latest
+            multiarch: s390x
+            gcc_cross: s390x-linux-gnu
+            qemu: true
+          - host_target: aarch64-apple-darwin
+            os: macos-latest
+          - host_target: i686-pc-windows-msvc
+            os: windows-latest
     runs-on: ${{ matrix.os }}
     env:
       HOST_TARGET: ${{ matrix.host_target }}
     steps:
       - uses: actions/checkout@v4
+      - name: install qemu
+        if: ${{ matrix.qemu }}
+        run: sudo apt install qemu-user qemu-user-binfmt
+      - name: install multiarch
+        if: ${{ matrix.multiarch != '' }}
+        run: |
+          # s390x, ppc64el need Ubuntu Ports to be in the mirror list
+          sudo bash -c "echo 'https://ports.ubuntu.com/	priority:4' >> /etc/apt/apt-mirrors.txt"
+          # Add architecture
+          sudo dpkg --add-architecture ${{ matrix.multiarch }}
+          sudo apt update
+          # Install needed packages
+          sudo apt install $(echo "libatomic1: zlib1g-dev:" | sed 's/:/:${{ matrix.multiarch }}/g')
       - uses: ./.github/workflows/setup
         with:
           toolchain_flags: "--host ${{ matrix.host_target }}"
 
-      # The `style` job only runs on Linux; this makes sure the Windows-host-specific
-      # code is also covered by clippy.
-      - name: Check clippy
-        if: ${{ matrix.os == 'windows-latest' }}
-        run: ./miri clippy -- -D warnings
+      # We set up the cross-compiler *after* the basic setup as setting CC would otherwise
+      # cause confusion.
+      - name: install gcc-cross
+        if: ${{ matrix.gcc_cross != '' }}
+        run: |
+          sudo apt install gcc-${{ matrix.gcc_cross }}
+          echo "Setting environment variables:"
+          echo "CC_${{ matrix.host_target }}=${{ matrix.gcc_cross }}-gcc" | tee -a $GITHUB_ENV
+          TARGET_UPPERCASE=$(echo ${{ matrix.host_target }} | tr '[:lower:]-' '[:upper:]_')
+          echo "CARGO_TARGET_${TARGET_UPPERCASE}_LINKER=${{ matrix.gcc_cross }}-gcc" | tee -a $GITHUB_ENV
 
-      - name: Test Miri
+      # The main test job! We don't run this in qemu as that is quite slow,
+      # so those targets only get the clippy check below.
+      - name: test Miri
+        if: ${{ !matrix.qemu }}
         run: ./ci/ci.sh
 
+      # The `style` job only runs on Linux; this makes sure the host-specific
+      # code is also covered by clippy.
+      - name: clippy
+        run: ./miri clippy -- -D warnings
+
   style:
     name: style checks
     runs-on: ubuntu-latest
@@ -51,8 +98,6 @@ jobs:
 
       - name: rustfmt
         run: ./miri fmt --check
-      - name: clippy
-        run: ./miri clippy -- -D warnings
       - name: clippy (no features)
         run: ./miri clippy --no-default-features -- -D warnings
       - name: clippy (all features)
@@ -73,7 +118,7 @@ jobs:
   # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
   # And they should be added below in `cron-fail-notify` as well.
   conclusion:
-    needs: [build, style, coverage]
+    needs: [test, style, coverage]
     # We need to ensure this job does *not* get skipped if its dependencies fail,
     # because a skipped job is considered a success by GitHub. So we have to
     # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
@@ -135,7 +180,7 @@ jobs:
   cron-fail-notify:
     name: cronjob failure notification
     runs-on: ubuntu-latest
-    needs: [build, style, coverage]
+    needs: [test, style, coverage]
     if: ${{ github.event_name == 'schedule' && failure() }}
     steps:
       # Send a Zulip notification
diff --git a/src/tools/miri/.github/workflows/setup/action.yml b/src/tools/miri/.github/workflows/setup/action.yml
index 146b432171e..9110e6947f4 100644
--- a/src/tools/miri/.github/workflows/setup/action.yml
+++ b/src/tools/miri/.github/workflows/setup/action.yml
@@ -2,6 +2,7 @@ name: "Miri CI setup"
 description: "Sets up Miri CI"
 inputs:
   toolchain_flags:
+    description: extra flags to pass to rustup-toolchain-install-master
     required: false
     default: ''
 runs:
@@ -31,18 +32,15 @@ runs:
             ~/.cargo/bin
             ~/.cargo/.crates.toml
             ~/.cargo/.crates2.json
-          key: cargo-${{ runner.os }}-${{ hashFiles('**/Cargo.lock', '.github/workflows/**/*.yml') }}
-          restore-keys: cargo-${{ runner.os }}
+          # Bump the version when something here changes that needs a cache reset.
+          key: cargo-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/Cargo.lock') }}-v1
+          restore-keys: cargo-${{ runner.os }}-${{ runner.arch }}
 
-      - name: Install rustup-toolchain-install-master
+      - name: Install the tools we need
         if: steps.cache.outputs.cache-hit != 'true'
         run: cargo install -f rustup-toolchain-install-master hyperfine
         shell: bash
 
-      - name: Install nightly toolchain
-        run: rustup toolchain install nightly --profile minimal
-        shell: bash
-
       - name: Install "master" toolchain
         run: |
           if [[ ${{ github.event_name }} == 'schedule' ]]; then
diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md
index 739f0702252..fef7f807e93 100644
--- a/src/tools/miri/CONTRIBUTING.md
+++ b/src/tools/miri/CONTRIBUTING.md
@@ -158,6 +158,15 @@ compiler that has `debug=true` set in `bootstrap.toml`.
 You can set `MIRI_BACKTRACE=1` to get a backtrace of where an
 evaluation error was originally raised.
 
+#### Tracing
+
+You can generate a Chrome trace file from a Miri execution by passing `--features=tracing` during the
+build and then setting `MIRI_TRACING=1` when running Miri. This will generate a `.json` file that
+you can visualize in [Perfetto](https://ui.perfetto.dev/). For example:
+
+```sh
+MIRI_TRACING=1 ./miri run --features=tracing tests/pass/hello.rs
+```
 
 ### UI testing
 
diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock
index 192d4f444c2..aa6f059cec2 100644
--- a/src/tools/miri/Cargo.lock
+++ b/src/tools/miri/Cargo.lock
@@ -81,6 +81,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "bincode"
+version = "1.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
+dependencies = [
+ "serde",
+]
+
+[[package]]
 name = "bitflags"
 version = "2.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -113,6 +122,26 @@ dependencies = [
 ]
 
 [[package]]
+name = "capstone"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "015ef5d5ca1743e3f94af9509ba6bd2886523cfee46e48d15c2ef5216fd4ac9a"
+dependencies = [
+ "capstone-sys",
+ "libc",
+]
+
+[[package]]
+name = "capstone-sys"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2267cb8d16a1e4197863ec4284ffd1aec26fe7e57c58af46b02590a0235809a0"
+dependencies = [
+ "cc",
+ "libc",
+]
+
+[[package]]
 name = "cargo-platform"
 version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -151,6 +180,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
+name = "cfg_aliases"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
+
+[[package]]
 name = "chrono"
 version = "0.4.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -224,7 +259,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
 dependencies = [
  "lazy_static",
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -243,7 +278,7 @@ dependencies = [
  "libc",
  "once_cell",
  "unicode-width 0.2.0",
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -298,7 +333,7 @@ dependencies = [
  "libc",
  "option-ext",
  "redox_users",
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -314,7 +349,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
 dependencies = [
  "libc",
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -334,6 +369,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
 
 [[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
 name = "generic-array"
 version = "0.14.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -401,6 +442,25 @@ dependencies = [
 ]
 
 [[package]]
+name = "ipc-channel"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fb8251fb7bcd9ccd3725ed8deae9fe7db8e586495c9eb5b0c52e6233e5e75ea"
+dependencies = [
+ "bincode",
+ "crossbeam-channel",
+ "fnv",
+ "lazy_static",
+ "libc",
+ "mio",
+ "rand 0.8.5",
+ "serde",
+ "tempfile",
+ "uuid",
+ "windows",
+]
+
+[[package]]
 name = "itoa"
 version = "1.0.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -534,23 +594,40 @@ dependencies = [
 ]
 
 [[package]]
+name = "mio"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
+dependencies = [
+ "libc",
+ "log",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
 name = "miri"
 version = "0.1.0"
 dependencies = [
  "aes",
  "bitflags",
+ "capstone",
  "chrono",
  "chrono-tz",
  "colored",
  "directories",
  "getrandom 0.3.2",
+ "ipc-channel",
  "libc",
  "libffi",
  "libloading",
  "measureme",
+ "nix",
  "rand 0.9.0",
  "regex",
  "rustc_version",
+ "serde",
+ "serde_json",
  "smallvec",
  "tempfile",
  "tikv-jemalloc-sys",
@@ -558,6 +635,18 @@ dependencies = [
 ]
 
 [[package]]
+name = "nix"
+version = "0.30.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "cfg_aliases",
+ "libc",
+]
+
+[[package]]
 name = "num-traits"
 version = "0.2.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -748,6 +837,8 @@ version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
 dependencies = [
+ "libc",
+ "rand_chacha 0.3.1",
  "rand_core 0.6.4",
 ]
 
@@ -757,13 +848,23 @@ version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
 dependencies = [
- "rand_chacha",
+ "rand_chacha 0.9.0",
  "rand_core 0.9.3",
  "zerocopy",
 ]
 
 [[package]]
 name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand_chacha"
 version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
@@ -777,6 +878,9 @@ name = "rand_core"
 version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom 0.2.15",
+]
 
 [[package]]
 name = "rand_core"
@@ -879,7 +983,7 @@ dependencies = [
  "errno",
  "libc",
  "linux-raw-sys",
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -993,7 +1097,7 @@ dependencies = [
  "getrandom 0.3.2",
  "once_cell",
  "rustix",
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -1148,6 +1252,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
 
 [[package]]
+name = "uuid"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
+dependencies = [
+ "getrandom 0.3.2",
+]
+
+[[package]]
 name = "valuable"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1242,6 +1355,79 @@ dependencies = [
 ]
 
 [[package]]
+name = "windows"
+version = "0.58.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6"
+dependencies = [
+ "windows-core",
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.58.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
+dependencies = [
+ "windows-implement",
+ "windows-interface",
+ "windows-result",
+ "windows-strings",
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.58.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.58.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
+dependencies = [
+ "windows-result",
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
 name = "windows-sys"
 version = "0.59.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml
index a314488bb25..75476d7923c 100644
--- a/src/tools/miri/Cargo.toml
+++ b/src/tools/miri/Cargo.toml
@@ -27,6 +27,7 @@ chrono = { version = "0.4.38", default-features = false }
 chrono-tz = "0.10"
 directories = "6"
 bitflags = "2.6"
+serde_json = { version = "1.0", optional = true }
 
 # Copied from `compiler/rustc/Cargo.toml`.
 # But only for some targets, it fails for others. Rustc configures this in its CI, but we can't
@@ -40,6 +41,12 @@ libc = "0.2"
 libffi = "4.0.0"
 libloading = "0.8"
 
+[target.'cfg(target_os = "linux")'.dependencies]
+nix = { version = "0.30.1", features = ["mman", "ptrace", "signal"] }
+ipc-channel = "0.19.0"
+serde = { version = "1.0.219", features = ["derive"] }
+capstone = "0.13"
+
 [dev-dependencies]
 ui_test = "0.29.1"
 colored = "2"
@@ -61,10 +68,10 @@ default = ["stack-cache"]
 genmc = []
 stack-cache = []
 stack-cache-consistency-check = ["stack-cache"]
+tracing = ["serde_json"]
 
 [lints.rust.unexpected_cfgs]
 level = "warn"
-check-cfg = ['cfg(bootstrap)']
 
 # Be aware that this file is inside a workspace when used via the
 # submodule in the rustc repo. That means there are many cargo features
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index 5554c7975ff..b05acff72b5 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -11,12 +11,12 @@ instance:
 * Not sufficiently aligned memory accesses and references
 * Violation of basic type invariants (a `bool` that is not 0 or 1, for example,
   or an invalid enum discriminant)
+* Data races and emulation of *some* weak memory effects, i.e.,
+  atomic reads can return outdated values
 * **Experimental**: Violations of the [Stacked Borrows] rules governing aliasing
   for reference types
 * **Experimental**: Violations of the [Tree Borrows] aliasing rules, as an optional
   alternative to [Stacked Borrows]
-* **Experimental**: Data races and emulation of weak memory effects, i.e.,
-  atomic reads can return outdated values.
 
 On top of that, Miri will also tell you about memory leaks: when there is memory
 still allocated at the end of the execution, and that memory is not reachable
@@ -419,6 +419,9 @@ to Miri failing to detect cases of undefined behavior in a program.
   Finally, the flag is **unsound** in the sense that Miri stops tracking details such as
   initialization and provenance on memory shared with native code, so it is easily possible to write
   code that has UB which is missed by Miri.
+* `-Zmiri-native-lib-enable-tracing` enables the WIP detailed tracing mode for invoking native code.
+  Note that this flag is only meaningful on Linux systems; other Unixes (currently) do not support
+  tracing mode.
 * `-Zmiri-measureme=<name>` enables `measureme` profiling for the interpreted program.
    This can be used to find which parts of your program are executing slowly under Miri.
    The profile is written out to a file inside a directory called `<name>`, and can be processed
@@ -592,7 +595,7 @@ Definite bugs found:
 * [Occasional memory leak in `std::mpsc` channels](https://github.com/rust-lang/rust/issues/121582) (original code in [crossbeam](https://github.com/crossbeam-rs/crossbeam/pull/1084))
 * [Weak-memory-induced memory leak in Windows thread-local storage](https://github.com/rust-lang/rust/pull/124281)
 * [A bug in the new `RwLock::downgrade` implementation](https://rust-lang.zulipchat.com/#narrow/channel/269128-miri/topic/Miri.20error.20library.20test) (caught by Miri before it landed in the Rust repo)
-* [Mockall reading unintialized memory when mocking `std::io::Read::read`, even if all expectations are satisfied](https://github.com/asomers/mockall/issues/647) (caught by Miri running Tokio's test suite)
+* [Mockall reading uninitialized memory when mocking `std::io::Read::read`, even if all expectations are satisfied](https://github.com/asomers/mockall/issues/647) (caught by Miri running Tokio's test suite)
 * [`ReentrantLock` not correctly dealing with reuse of addresses for TLS storage of different threads](https://github.com/rust-lang/rust/pull/141248)
 
 Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment):
diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs
index a5e019a8ea9..b72b974bdbd 100644
--- a/src/tools/miri/cargo-miri/src/phases.rs
+++ b/src/tools/miri/cargo-miri/src/phases.rs
@@ -176,11 +176,6 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
     // Set `--target-dir` to `miri` inside the original target directory.
     let target_dir = get_target_dir(&metadata);
     cmd.arg("--target-dir").arg(target_dir);
-    // Only when running in x.py (where we are running with beta cargo): set `RUSTC_STAGE`.
-    // Will have to be removed on next bootstrap bump. tag: cfg(bootstrap).
-    if env::var_os("RUSTC_STAGE").is_some() {
-        cmd.arg("-Zdoctest-xcompile");
-    }
 
     // *After* we set all the flags that need setting, forward everything else. Make sure to skip
     // `--target-dir` (which would otherwise be set twice).
diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh
index 8941af681a4..5767d178279 100755
--- a/src/tools/miri/ci/ci.sh
+++ b/src/tools/miri/ci/ci.sh
@@ -143,11 +143,36 @@ case $HOST_TARGET in
     GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests
     # Extra tier 1
     MANY_SEEDS=64 TEST_TARGET=i686-unknown-linux-gnu run_tests
-    MANY_SEEDS=64 TEST_TARGET=aarch64-unknown-linux-gnu run_tests
     MANY_SEEDS=64 TEST_TARGET=x86_64-apple-darwin run_tests
     MANY_SEEDS=64 TEST_TARGET=x86_64-pc-windows-gnu run_tests
+    ;;
+  i686-unknown-linux-gnu)
+    # Host
+    # Without GC_STRESS as this is a slow runner.
+    MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 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=aarch64-linux-android  run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency 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
+    TEST_TARGET=thumbv7em-none-eabihf  run_tests_minimal no_std
+    ;;
+  aarch64-unknown-linux-gnu)
+    # Host
+    GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests
     # Extra tier 1 candidate
     MANY_SEEDS=64 TEST_TARGET=aarch64-pc-windows-msvc run_tests
+    # Extra tier 2
+    MANY_SEEDS=16 TEST_TARGET=arm-unknown-linux-gnueabi run_tests # 32bit ARM
+    MANY_SEEDS=16 TEST_TARGET=aarch64-pc-windows-gnullvm run_tests # gnullvm ABI
+    MANY_SEEDS=16 TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture of choice
+    # Custom target JSON file
+    TEST_TARGET=tests/x86_64-unknown-kernel.json MIRI_NO_STD=1 run_tests_minimal no_std
+    ;;
+  armv7-unknown-linux-gnueabihf)
+    # Host
+    GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests
     ;;
   aarch64-apple-darwin)
     # Host
@@ -155,30 +180,16 @@ case $HOST_TARGET in
     # Extra tier 1
     MANY_SEEDS=64 TEST_TARGET=i686-pc-windows-gnu run_tests
     MANY_SEEDS=64 TEST_TARGET=x86_64-pc-windows-msvc CARGO_MIRI_ENV=1 run_tests
-    # Extra tier 2
-    MANY_SEEDS=16 TEST_TARGET=arm-unknown-linux-gnueabi run_tests # 32bit ARM
-    MANY_SEEDS=16 TEST_TARGET=aarch64-pc-windows-gnullvm run_tests # gnullvm ABI
-    MANY_SEEDS=16 TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture of choice
     # Not officially supported tier 2
     MANY_SEEDS=16 TEST_TARGET=mips-unknown-linux-gnu run_tests # a 32bit big-endian target, and also a target without 64bit atomics
     MANY_SEEDS=16 TEST_TARGET=x86_64-unknown-illumos run_tests
     MANY_SEEDS=16 TEST_TARGET=x86_64-pc-solaris run_tests
     MANY_SEEDS=16 TEST_TARGET=x86_64-unknown-freebsd run_tests
     MANY_SEEDS=16 TEST_TARGET=i686-unknown-freebsd 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=aarch64-linux-android  run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency 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
-    TEST_TARGET=thumbv7em-none-eabihf  run_tests_minimal no_std
-    # Custom target JSON file
-    TEST_TARGET=tests/x86_64-unknown-kernel.json MIRI_NO_STD=1 run_tests_minimal no_std
     ;;
   i686-pc-windows-msvc)
     # Host
-    # Without GC_STRESS and with reduced many-seeds count as this is the slowest runner.
-    # (The macOS runner checks windows-msvc with full many-seeds count.)
+    # Without GC_STRESS as this is the slowest runner.
     MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 run_tests
     # Extra tier 1
     # We really want to ensure a Linux target works on a Windows host,
diff --git a/src/tools/miri/etc/rust_analyzer_helix.toml b/src/tools/miri/etc/rust_analyzer_helix.toml
index 62db463a191..9bfb09120d8 100644
--- a/src/tools/miri/etc/rust_analyzer_helix.toml
+++ b/src/tools/miri/etc/rust_analyzer_helix.toml
@@ -9,23 +9,21 @@ linkedProjects = [
 ]
 
 [language-server.rust-analyzer.config.check]
-invocationLocation = "root"
 invocationStrategy = "once"
 overrideCommand = [
-    "env",
-    "MIRI_AUTO_OPS=no",
     "./miri",
     "clippy", # make this `check` when working with a locally built rustc
     "--message-format=json",
 ]
 
+[language-server.rust-analyzer.config.cargo.extraEnv]
+MIRI_AUTO_OPS = "no"
+MIRI_IN_RA = "1"
+
 # Contrary to what the name suggests, this also affects proc macros.
-[language-server.rust-analyzer.config.buildScripts]
-invocationLocation = "root"
+[language-server.rust-analyzer.config.cargo.buildScripts]
 invocationStrategy = "once"
 overrideCommand = [
-    "env",
-    "MIRI_AUTO_OPS=no",
     "./miri",
     "check",
     "--message-format=json",
diff --git a/src/tools/miri/miri b/src/tools/miri/miri
index b1b146d7990..549998ae44a 100755
--- a/src/tools/miri/miri
+++ b/src/tools/miri/miri
@@ -2,20 +2,24 @@
 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
-TOOLCHAIN="+nightly"
+TARGET_DIR="$ROOT_DIR"/miri-script/target
+# Prepare cargo invocation.
+# We have to overwrite the toolchain since `+miri` might be activated and not installed.
+TOOLCHAIN="+stable"
+CARGO_FLAGS=("-q")
 # 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.
+# Also set `-Zroot-dir` so that RA can identify where the error occurred.
 if [ -n "$MIRI_IN_RA" ]; then
-  MESSAGE_FORMAT="--message-format=json"
   TOOLCHAIN=""
-  MIRI_SCRIPT_TARGET_DIR="$MIRI_SCRIPT_TARGET_DIR"/ra
+  CARGO_FLAGS+=("--message-format=json" "-Zroot-dir=$ROOT_DIR")
+  TARGET_DIR="$ROOT_DIR"/target
 fi
-# We need a nightly toolchain, for `-Zroot-dir`.
-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 )
-# Instead of doing just `cargo run --manifest-path .. $@`, we invoke miri-script binary directly. Invoking `cargo run` goes through
-# rustup (that sets it's own environmental variables), which is undesirable.
-"$MIRI_SCRIPT_TARGET_DIR"/debug/miri-script "$@"
+# Run cargo.
+cargo $TOOLCHAIN build --manifest-path "$ROOT_DIR"/miri-script/Cargo.toml \
+  --target-dir "$TARGET_DIR" "${CARGO_FLAGS[@]}" || \
+  ( echo "Failed to build miri-script. Is the 'stable' toolchain installed?"; exit 1 )
+# Instead of doing just `cargo run --manifest-path .. $@`, we invoke miri-script binary directly.
+# Invoking `cargo run` goes through rustup (that sets it's own environmental variables), which is
+# undesirable.
+"$TARGET_DIR"/debug/miri-script "$@"
diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs
index 86362145d47..e948beef004 100644
--- a/src/tools/miri/miri-script/src/commands.rs
+++ b/src/tools/miri/miri-script/src/commands.rs
@@ -32,6 +32,7 @@ impl MiriEnv {
         &mut self,
         quiet: bool,
         target: Option<impl AsRef<OsStr>>,
+        features: &[String],
     ) -> Result<PathBuf> {
         if let Some(miri_sysroot) = self.sh.var_os("MIRI_SYSROOT") {
             // Sysroot already set, use that.
@@ -39,8 +40,8 @@ impl MiriEnv {
         }
 
         // Make sure everything is built. Also Miri itself.
-        self.build(".", &[], quiet)?;
-        self.build("cargo-miri", &[], quiet)?;
+        self.build(".", features, &[], quiet)?;
+        self.build("cargo-miri", &[], &[], quiet)?;
 
         let target_flag = if let Some(target) = &target {
             vec![OsStr::new("--target"), target.as_ref()]
@@ -58,7 +59,7 @@ impl MiriEnv {
         }
 
         let mut cmd = self
-            .cargo_cmd("cargo-miri", "run")
+            .cargo_cmd("cargo-miri", "run", &[])
             .arg("--quiet")
             .arg("--")
             .args(&["miri", "setup", "--print-sysroot"])
@@ -90,7 +91,9 @@ impl Command {
             Self::fmt(vec![])?;
         }
         if auto_clippy {
-            Self::clippy(vec![])?;
+            // no features for auto actions, see
+            // https://github.com/rust-lang/miri/pull/4396#discussion_r2149654845
+            Self::clippy(vec![], vec![])?;
         }
 
         Ok(())
@@ -175,16 +178,16 @@ impl Command {
         }
         // Then run the actual command.
         match self {
-            Command::Install { flags } => Self::install(flags),
-            Command::Build { flags } => Self::build(flags),
-            Command::Check { flags } => Self::check(flags),
-            Command::Test { bless, flags, target, coverage } =>
-                Self::test(bless, flags, target, coverage),
-            Command::Run { dep, verbose, target, edition, flags } =>
-                Self::run(dep, verbose, target, edition, flags),
-            Command::Doc { flags } => Self::doc(flags),
+            Command::Install { features, flags } => Self::install(features, flags),
+            Command::Build { features, flags } => Self::build(features, flags),
+            Command::Check { features, flags } => Self::check(features, flags),
+            Command::Test { bless, target, coverage, features, flags } =>
+                Self::test(bless, target, coverage, features, flags),
+            Command::Run { dep, verbose, target, edition, features, flags } =>
+                Self::run(dep, verbose, target, edition, features, flags),
+            Command::Doc { features, flags } => Self::doc(features, flags),
             Command::Fmt { flags } => Self::fmt(flags),
-            Command::Clippy { flags } => Self::clippy(flags),
+            Command::Clippy { features, flags } => Self::clippy(features, flags),
             Command::Bench { target, no_install, save_baseline, load_baseline, benches } =>
                 Self::bench(target, no_install, save_baseline, load_baseline, benches),
             Command::Toolchain { flags } => Self::toolchain(flags),
@@ -228,11 +231,6 @@ impl Command {
         cmd!(sh, "rustup override set miri").run()?;
         // Cleanup.
         cmd!(sh, "cargo clean").run()?;
-        // Call `cargo metadata` on the sources in case that changes the lockfile
-        // (which fails under some setups when it is done from inside vscode).
-        let sysroot = cmd!(sh, "rustc --print sysroot").read()?;
-        let sysroot = sysroot.trim();
-        cmd!(sh, "cargo metadata --format-version 1 --manifest-path {sysroot}/lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml").ignore_stdout().run()?;
         Ok(())
     }
 
@@ -494,7 +492,7 @@ impl Command {
 
         if !no_install {
             // Make sure we have an up-to-date Miri installed and selected the right toolchain.
-            Self::install(vec![])?;
+            Self::install(vec![], vec![])?;
         }
         let results_json_dir = if save_baseline.is_some() || load_baseline.is_some() {
             Some(TempDir::new()?)
@@ -601,47 +599,48 @@ impl Command {
         Ok(())
     }
 
-    fn install(flags: Vec<String>) -> Result<()> {
+    fn install(features: Vec<String>, flags: Vec<String>) -> Result<()> {
         let e = MiriEnv::new()?;
-        e.install_to_sysroot(e.miri_dir.clone(), &flags)?;
-        e.install_to_sysroot(path!(e.miri_dir / "cargo-miri"), &flags)?;
+        e.install_to_sysroot(".", &features, &flags)?;
+        e.install_to_sysroot("cargo-miri", &[], &flags)?;
         Ok(())
     }
 
-    fn build(flags: Vec<String>) -> Result<()> {
+    fn build(features: Vec<String>, flags: Vec<String>) -> Result<()> {
         let e = MiriEnv::new()?;
-        e.build(".", &flags, /* quiet */ false)?;
-        e.build("cargo-miri", &flags, /* quiet */ false)?;
+        e.build(".", &features, &flags, /* quiet */ false)?;
+        e.build("cargo-miri", &[], &flags, /* quiet */ false)?;
         Ok(())
     }
 
-    fn check(flags: Vec<String>) -> Result<()> {
+    fn check(features: Vec<String>, flags: Vec<String>) -> Result<()> {
         let e = MiriEnv::new()?;
-        e.check(".", &flags)?;
-        e.check("cargo-miri", &flags)?;
+        e.check(".", &features, &flags)?;
+        e.check("cargo-miri", &[], &flags)?;
         Ok(())
     }
 
-    fn doc(flags: Vec<String>) -> Result<()> {
+    fn doc(features: Vec<String>, flags: Vec<String>) -> Result<()> {
         let e = MiriEnv::new()?;
-        e.doc(".", &flags)?;
-        e.doc("cargo-miri", &flags)?;
+        e.doc(".", &features, &flags)?;
+        e.doc("cargo-miri", &[], &flags)?;
         Ok(())
     }
 
-    fn clippy(flags: Vec<String>) -> Result<()> {
+    fn clippy(features: Vec<String>, flags: Vec<String>) -> Result<()> {
         let e = MiriEnv::new()?;
-        e.clippy(".", &flags)?;
-        e.clippy("cargo-miri", &flags)?;
-        e.clippy("miri-script", &flags)?;
+        e.clippy(".", &features, &flags)?;
+        e.clippy("cargo-miri", &[], &flags)?;
+        e.clippy("miri-script", &[], &flags)?;
         Ok(())
     }
 
     fn test(
         bless: bool,
-        mut flags: Vec<String>,
         target: Option<String>,
         coverage: bool,
+        features: Vec<String>,
+        mut flags: Vec<String>,
     ) -> Result<()> {
         let mut e = MiriEnv::new()?;
 
@@ -652,7 +651,7 @@ impl Command {
         }
 
         // Prepare a sysroot. (Also builds cargo-miri, which we need.)
-        e.build_miri_sysroot(/* quiet */ false, target.as_deref())?;
+        e.build_miri_sysroot(/* quiet */ false, target.as_deref(), &features)?;
 
         // Forward information to test harness.
         if bless {
@@ -672,10 +671,10 @@ impl Command {
 
         // Then test, and let caller control flags.
         // Only in root project as `cargo-miri` has no tests.
-        e.test(".", &flags)?;
+        e.test(".", &features, &flags)?;
 
         if let Some(coverage) = &coverage {
-            coverage.show_coverage_report(&e)?;
+            coverage.show_coverage_report(&e, &features)?;
         }
 
         Ok(())
@@ -686,23 +685,29 @@ impl Command {
         verbose: bool,
         target: Option<String>,
         edition: Option<String>,
+        features: Vec<String>,
         flags: Vec<String>,
     ) -> Result<()> {
         let mut e = MiriEnv::new()?;
 
         // Preparation: get a sysroot, and get the miri binary.
-        let miri_sysroot = e.build_miri_sysroot(/* quiet */ !verbose, target.as_deref())?;
-        let miri_bin =
-            e.build_get_binary(".").context("failed to get filename of miri executable")?;
+        let miri_sysroot =
+            e.build_miri_sysroot(/* quiet */ !verbose, target.as_deref(), &features)?;
+        let miri_bin = e
+            .build_get_binary(".", &features)
+            .context("failed to get filename of miri executable")?;
 
         // More flags that we will pass before `flags`
         // (because `flags` may contain `--`).
         let mut early_flags = Vec::<OsString>::new();
 
         // In `dep` mode, the target is already passed via `MIRI_TEST_TARGET`
-        if !dep && let Some(target) = &target {
-            early_flags.push("--target".into());
-            early_flags.push(target.into());
+        #[expect(clippy::collapsible_if)] // we need to wait until this is stable
+        if !dep {
+            if let Some(target) = &target {
+                early_flags.push("--target".into());
+                early_flags.push(target.into());
+            }
         }
         early_flags.push("--edition".into());
         early_flags.push(edition.as_deref().unwrap_or("2021").into());
@@ -718,7 +723,7 @@ impl Command {
         // The basic command that executes the Miri driver.
         let mut cmd = if dep {
             // We invoke the test suite as that has all the logic for running with dependencies.
-            e.cargo_cmd(".", "test")
+            e.cargo_cmd(".", "test", &features)
                 .args(&["--test", "ui"])
                 .args(quiet_flag)
                 .arg("--")
@@ -730,8 +735,11 @@ impl Command {
         // Add Miri flags
         let mut cmd = cmd.args(&miri_flags).args(&early_flags).args(&flags);
         // For `--dep` we also need to set the target in the env var.
-        if dep && let Some(target) = &target {
-            cmd = cmd.env("MIRI_TEST_TARGET", target);
+        #[expect(clippy::collapsible_if)] // we need to wait until this is stable
+        if dep {
+            if let Some(target) = &target {
+                cmd = cmd.env("MIRI_TEST_TARGET", target);
+            }
         }
         // Finally, run the thing.
         Ok(cmd.run()?)
diff --git a/src/tools/miri/miri-script/src/coverage.rs b/src/tools/miri/miri-script/src/coverage.rs
index 8cafcea0d16..cdf2bbb9330 100644
--- a/src/tools/miri/miri-script/src/coverage.rs
+++ b/src/tools/miri/miri-script/src/coverage.rs
@@ -49,7 +49,7 @@ impl CoverageReport {
 
     /// show_coverage_report will print coverage information using the artifact
     /// files in `self.path`.
-    pub fn show_coverage_report(&self, e: &MiriEnv) -> Result<()> {
+    pub fn show_coverage_report(&self, e: &MiriEnv, features: &[String]) -> Result<()> {
         let profraw_files = self.profraw_files()?;
 
         let profdata_bin = path!(e.libdir / ".." / "bin" / "llvm-profdata");
@@ -63,8 +63,9 @@ impl CoverageReport {
 
         // Create the coverage report.
         let cov_bin = path!(e.libdir / ".." / "bin" / "llvm-cov");
-        let miri_bin =
-            e.build_get_binary(".").context("failed to get filename of miri executable")?;
+        let miri_bin = e
+            .build_get_binary(".", features)
+            .context("failed to get filename of miri executable")?;
         cmd!(
             e.sh,
             "{cov_bin} report --instr-profile={merged_file} --object {miri_bin} --sources src/"
diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs
index 6aab2f79bd7..673d658cf1d 100644
--- a/src/tools/miri/miri-script/src/main.rs
+++ b/src/tools/miri/miri-script/src/main.rs
@@ -14,24 +14,40 @@ pub enum Command {
     /// Sets up the rpath such that the installed binary should work in any
     /// working directory.
     Install {
+        /// Pass features to cargo invocations on the "miri" crate in the root. This option does
+        /// **not** apply to other crates, so e.g. these features won't be used on "cargo-miri".
+        #[arg(long, value_delimiter = ',', action = clap::ArgAction::Append)]
+        features: Vec<String>,
         /// Flags that are passed through to `cargo install`.
         #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
         flags: Vec<String>,
     },
     /// Build Miri.
     Build {
+        /// Pass features to cargo invocations on the "miri" crate in the root. This option does
+        /// **not** apply to other crates, so e.g. these features won't be used on "cargo-miri".
+        #[arg(long, value_delimiter = ',', action = clap::ArgAction::Append)]
+        features: Vec<String>,
         /// Flags that are passed through to `cargo build`.
         #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
         flags: Vec<String>,
     },
     /// Check Miri.
     Check {
+        /// Pass features to cargo invocations on the "miri" crate in the root. This option does
+        /// **not** apply to other crates, so e.g. these features won't be used on "cargo-miri".
+        #[arg(long, value_delimiter = ',', action = clap::ArgAction::Append)]
+        features: Vec<String>,
         /// Flags that are passed through to `cargo check`.
         #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
         flags: Vec<String>,
     },
     /// Check Miri with Clippy.
     Clippy {
+        /// Pass features to cargo invocations on the "miri" crate in the root. This option does
+        /// **not** apply to other crates, so e.g. these features won't be used on "cargo-miri".
+        #[arg(long, value_delimiter = ',', action = clap::ArgAction::Append)]
+        features: Vec<String>,
         /// Flags that are passed through to `cargo clippy`.
         #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
         flags: Vec<String>,
@@ -47,6 +63,10 @@ pub enum Command {
         /// Produce coverage report.
         #[arg(long)]
         coverage: bool,
+        /// Pass features to cargo invocations on the "miri" crate in the root. This option does
+        /// **not** apply to other crates, so e.g. these features won't be used on "cargo-miri".
+        #[arg(long, value_delimiter = ',', action = clap::ArgAction::Append)]
+        features: Vec<String>,
         /// Flags that are passed through to the test harness.
         #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
         flags: Vec<String>,
@@ -67,6 +87,10 @@ pub enum Command {
         /// The Rust edition.
         #[arg(long)]
         edition: Option<String>,
+        /// Pass features to cargo invocations on the "miri" crate in the root. This option does
+        /// **not** apply to other crates, so e.g. these features won't be used on "cargo-miri".
+        #[arg(long, value_delimiter = ',', action = clap::ArgAction::Append)]
+        features: Vec<String>,
         /// Flags that are passed through to `miri`.
         ///
         /// The flags set in `MIRIFLAGS` are added in front of these flags.
@@ -75,6 +99,10 @@ pub enum Command {
     },
     /// Build documentation.
     Doc {
+        /// Pass features to cargo invocations on the "miri" crate in the root. This option does
+        /// **not** apply to other crates, so e.g. these features won't be used on "cargo-miri".
+        #[arg(long, value_delimiter = ',', action = clap::ArgAction::Append)]
+        features: Vec<String>,
         /// Flags that are passed through to `cargo doc`.
         #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
         flags: Vec<String>,
@@ -144,13 +172,13 @@ impl Command {
         }
 
         match self {
-            Self::Install { flags }
-            | Self::Build { flags }
-            | Self::Check { flags }
-            | Self::Doc { flags }
+            Self::Install { flags, .. }
+            | Self::Build { flags, .. }
+            | Self::Check { flags, .. }
+            | Self::Doc { flags, .. }
             | Self::Fmt { flags }
             | Self::Toolchain { flags }
-            | Self::Clippy { flags }
+            | Self::Clippy { flags, .. }
             | Self::Run { flags, .. }
             | Self::Test { flags, .. } => {
                 flags.extend(remainder);
diff --git a/src/tools/miri/miri-script/src/util.rs b/src/tools/miri/miri-script/src/util.rs
index 5c2a055990f..c100cf195ba 100644
--- a/src/tools/miri/miri-script/src/util.rs
+++ b/src/tools/miri/miri-script/src/util.rs
@@ -26,6 +26,12 @@ pub fn flagsplit(flags: &str) -> Vec<String> {
     flags.split(' ').map(str::trim).filter(|s| !s.is_empty()).map(str::to_string).collect()
 }
 
+/// Turns a list of features into a list of arguments to pass to cargo invocations.
+/// Each feature will go in its own argument, e.g. "--features feat1 --features feat2".
+fn features_to_args(features: &[String]) -> impl IntoIterator<Item = &str> {
+    features.iter().flat_map(|feat| ["--features", feat])
+}
+
 /// Some extra state we track for building Miri, such as the right RUSTFLAGS.
 pub struct MiriEnv {
     /// miri_dir is the root of the miri repository checkout we are working in.
@@ -116,44 +122,70 @@ impl MiriEnv {
         Ok(MiriEnv { miri_dir, toolchain, sh, sysroot, cargo_extra_flags, libdir })
     }
 
-    pub fn cargo_cmd(&self, crate_dir: impl AsRef<OsStr>, cmd: &str) -> Cmd<'_> {
+    /// Make sure the `features` you pass here exist for the specified `crate_dir`. For example, the
+    /// "--features" parameter of [crate::Command]s is intended only for the "miri" root crate.
+    pub fn cargo_cmd(
+        &self,
+        crate_dir: impl AsRef<OsStr>,
+        cmd: &str,
+        features: &[String],
+    ) -> Cmd<'_> {
         let MiriEnv { toolchain, cargo_extra_flags, .. } = self;
         let manifest_path = path!(self.miri_dir / crate_dir.as_ref() / "Cargo.toml");
+        let features = features_to_args(features);
         cmd!(
             self.sh,
-            "cargo +{toolchain} {cmd} {cargo_extra_flags...} --manifest-path {manifest_path}"
+            "cargo +{toolchain} {cmd} {cargo_extra_flags...} --manifest-path {manifest_path} {features...}"
         )
     }
 
+    /// Make sure the `features` you pass here exist for the specified `crate_dir`. For example, the
+    /// "--features" parameter of [crate::Command]s is intended only for the "miri" root crate.
     pub fn install_to_sysroot(
         &self,
-        path: impl AsRef<OsStr>,
+        crate_dir: impl AsRef<OsStr>,
+        features: &[String],
         args: impl IntoIterator<Item = impl AsRef<OsStr>>,
     ) -> Result<()> {
         let MiriEnv { sysroot, toolchain, cargo_extra_flags, .. } = self;
-        let path = path!(self.miri_dir / path.as_ref());
+        let path = path!(self.miri_dir / crate_dir.as_ref());
+        let features = features_to_args(features);
         // Install binaries to the miri toolchain's `sysroot` so they do not interact with other toolchains.
         // (Not using `cargo_cmd` as `install` is special and doesn't use `--manifest-path`.)
-        cmd!(self.sh, "cargo +{toolchain} install {cargo_extra_flags...} --path {path} --force --root {sysroot} {args...}").run()?;
+        cmd!(self.sh, "cargo +{toolchain} install {cargo_extra_flags...} --path {path} --force --root {sysroot} {features...} {args...}").run()?;
         Ok(())
     }
 
-    pub fn build(&self, crate_dir: impl AsRef<OsStr>, args: &[String], quiet: bool) -> Result<()> {
+    pub fn build(
+        &self,
+        crate_dir: impl AsRef<OsStr>,
+        features: &[String],
+        args: &[String],
+        quiet: bool,
+    ) -> Result<()> {
         let quiet_flag = if quiet { Some("--quiet") } else { None };
         // We build all targets, since building *just* the bin target doesnot include
         // `dev-dependencies` and that changes feature resolution. This also gets us more
         // parallelism in `./miri test` as we build Miri and its tests together.
-        let mut cmd =
-            self.cargo_cmd(crate_dir, "build").args(&["--all-targets"]).args(quiet_flag).args(args);
+        let mut cmd = self
+            .cargo_cmd(crate_dir, "build", features)
+            .args(&["--all-targets"])
+            .args(quiet_flag)
+            .args(args);
         cmd.set_quiet(quiet);
         cmd.run()?;
         Ok(())
     }
 
     /// Returns the path to the main crate binary. Assumes that `build` has been called before.
-    pub fn build_get_binary(&self, crate_dir: impl AsRef<OsStr>) -> Result<PathBuf> {
-        let cmd =
-            self.cargo_cmd(crate_dir, "build").args(&["--all-targets", "--message-format=json"]);
+    pub fn build_get_binary(
+        &self,
+        crate_dir: impl AsRef<OsStr>,
+        features: &[String],
+    ) -> Result<PathBuf> {
+        let cmd = self
+            .cargo_cmd(crate_dir, "build", features)
+            .args(&["--all-targets", "--message-format=json"]);
         let output = cmd.output()?;
         let mut bin = None;
         for line in output.stdout.lines() {
@@ -174,23 +206,43 @@ impl MiriEnv {
         bin.ok_or_else(|| anyhow!("found no binary in cargo output"))
     }
 
-    pub fn check(&self, crate_dir: impl AsRef<OsStr>, args: &[String]) -> Result<()> {
-        self.cargo_cmd(crate_dir, "check").arg("--all-targets").args(args).run()?;
+    pub fn check(
+        &self,
+        crate_dir: impl AsRef<OsStr>,
+        features: &[String],
+        args: &[String],
+    ) -> Result<()> {
+        self.cargo_cmd(crate_dir, "check", features).arg("--all-targets").args(args).run()?;
         Ok(())
     }
 
-    pub fn doc(&self, crate_dir: impl AsRef<OsStr>, args: &[String]) -> Result<()> {
-        self.cargo_cmd(crate_dir, "doc").args(args).run()?;
+    pub fn doc(
+        &self,
+        crate_dir: impl AsRef<OsStr>,
+        features: &[String],
+        args: &[String],
+    ) -> Result<()> {
+        self.cargo_cmd(crate_dir, "doc", features).args(args).run()?;
         Ok(())
     }
 
-    pub fn clippy(&self, crate_dir: impl AsRef<OsStr>, args: &[String]) -> Result<()> {
-        self.cargo_cmd(crate_dir, "clippy").arg("--all-targets").args(args).run()?;
+    pub fn clippy(
+        &self,
+        crate_dir: impl AsRef<OsStr>,
+        features: &[String],
+        args: &[String],
+    ) -> Result<()> {
+        self.cargo_cmd(crate_dir, "clippy", features).arg("--all-targets").args(args).run()?;
         Ok(())
     }
 
-    pub fn test(&self, crate_dir: impl AsRef<OsStr>, args: &[String]) -> Result<()> {
-        self.cargo_cmd(crate_dir, "test").args(args).run()?;
+    pub fn test(
+        &self,
+        crate_dir: impl AsRef<OsStr>,
+        features: &[String],
+        args: &[String],
+    ) -> Result<()> {
+        self.cargo_cmd(crate_dir, "test", features).args(args).run()?;
         Ok(())
     }
 
diff --git a/src/tools/miri/miri.bat b/src/tools/miri/miri.bat
index b046b6310dd..6f9a8f38d65 100644
--- a/src/tools/miri/miri.bat
+++ b/src/tools/miri/miri.bat
@@ -5,8 +5,8 @@ set MIRI_SCRIPT_TARGET_DIR=%0\..\miri-script\target
 
 :: If any other steps are added, the "|| exit /b" must be appended to early
 :: return from the script. If not, it will continue execution.
-cargo +nightly build %CARGO_EXTRA_FLAGS% -q --target-dir %MIRI_SCRIPT_TARGET_DIR% --manifest-path %0\..\miri-script\Cargo.toml ^
-  || (echo Failed to build miri-script. Is the 'nightly' toolchain installed? & exit /b)
+cargo +stable build %CARGO_EXTRA_FLAGS% -q --target-dir %MIRI_SCRIPT_TARGET_DIR% --manifest-path %0\..\miri-script\Cargo.toml ^
+  || (echo Failed to build miri-script. Is the 'stable' toolchain installed? & exit /b)
 
 :: Forwards all arguments to this file to the executable.
 :: We invoke the binary directly to avoid going through rustup, which would set some extra
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 90c6e31e9d1..0130cf13a45 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-0cbc0764380630780a275c437260e4d4d5f28c92
+733b47ea4b1b86216f14ef56e49440c33933f230
diff --git a/src/tools/miri/rustfmt.toml b/src/tools/miri/rustfmt.toml
index 49650d8486c..92fd22b7f55 100644
--- a/src/tools/miri/rustfmt.toml
+++ b/src/tools/miri/rustfmt.toml
@@ -8,3 +8,8 @@ imports_granularity = "Module"
 force_multiline_blocks = true
 match_arm_blocks = false
 match_arm_leading_pipes = "Preserve"
+
+ignore = [
+    # This file is copy-pasted from the tracing_chrome crate and should remain like the original.
+    "src/bin/log/tracing_chrome.rs"
+]
diff --git a/src/tools/miri/src/alloc/isolated_alloc.rs b/src/tools/miri/src/alloc/isolated_alloc.rs
index 3a7879f372a..a7bb9b4da75 100644
--- a/src/tools/miri/src/alloc/isolated_alloc.rs
+++ b/src/tools/miri/src/alloc/isolated_alloc.rs
@@ -1,5 +1,7 @@
-use std::alloc::{self, Layout};
+use std::alloc::Layout;
+use std::ptr::NonNull;
 
+use nix::sys::mman;
 use rustc_index::bit_set::DenseBitSet;
 
 /// How many bytes of memory each bit in the bitset represents.
@@ -11,8 +13,8 @@ const COMPRESSION_FACTOR: usize = 4;
 pub struct IsolatedAlloc {
     /// Pointers to page-aligned memory that has been claimed by the allocator.
     /// Every pointer here must point to a page-sized allocation claimed via
-    /// the global allocator. These pointers are used for "small" allocations.
-    page_ptrs: Vec<*mut u8>,
+    /// mmap. These pointers are used for "small" allocations.
+    page_ptrs: Vec<NonNull<u8>>,
     /// Metadata about which bytes have been allocated on each page. The length
     /// of this vector must be the same as that of `page_ptrs`, and the domain
     /// size of the bitset must be exactly `page_size / COMPRESSION_FACTOR`.
@@ -24,7 +26,7 @@ pub struct IsolatedAlloc {
     page_infos: Vec<DenseBitSet<usize>>,
     /// Pointers to multiple-page-sized allocations. These must also be page-aligned,
     /// with their size stored as the second element of the vector.
-    huge_ptrs: Vec<(*mut u8, usize)>,
+    huge_ptrs: Vec<(NonNull<u8>, usize)>,
     /// The host (not emulated) page size.
     page_size: usize,
 }
@@ -52,20 +54,26 @@ impl IsolatedAlloc {
         Layout::from_size_align(size, align).unwrap()
     }
 
-    /// Returns the layout used to allocate the pages that hold small allocations.
+    /// For greater-than-page-sized allocations, returns the allocation size we need to request
+    /// including the slack we need to satisfy the alignment request.
     #[inline]
-    fn page_layout(&self) -> Layout {
-        Layout::from_size_align(self.page_size, self.page_size).unwrap()
-    }
-
-    /// If the allocation is greater than a page, then round to the nearest page #.
-    #[inline]
-    fn huge_normalized_layout(layout: Layout, page_size: usize) -> Layout {
+    fn huge_normalized_layout(&self, layout: Layout) -> usize {
         // Allocate in page-sized chunks
-        let size = layout.size().next_multiple_of(page_size);
+        let size = layout.size().next_multiple_of(self.page_size);
         // And make sure the align is at least one page
-        let align = std::cmp::max(layout.align(), page_size);
-        Layout::from_size_align(size, align).unwrap()
+        let align = std::cmp::max(layout.align(), self.page_size);
+        // pg_count gives us the # of pages needed to satisfy the size. For
+        // align > page_size where align = n * page_size, a sufficently-aligned
+        // address must exist somewhere in the range of
+        // some_page_aligned_address..some_page_aligned_address + (n-1) * page_size
+        // (since if some_page_aligned_address + n * page_size is sufficently aligned,
+        // then so is some_page_aligned_address itself per the definition of n, so we
+        // can avoid using that 1 extra page).
+        // Thus we allocate n-1 extra pages
+        let pg_count = size.div_ceil(self.page_size);
+        let extra_pages = align.strict_div(self.page_size).saturating_sub(1);
+
+        pg_count.strict_add(extra_pages).strict_mul(self.page_size)
     }
 
     /// Determined whether a given normalized (size, align) should be sent to
@@ -78,7 +86,7 @@ impl IsolatedAlloc {
     /// Allocates memory as described in `Layout`. This memory should be deallocated
     /// by calling `dealloc` on this same allocator.
     ///
-    /// SAFETY: See `alloc::alloc()`
+    /// SAFETY: See `alloc::alloc()`.
     pub unsafe fn alloc(&mut self, layout: Layout) -> *mut u8 {
         // SAFETY: Upheld by caller
         unsafe { self.allocate(layout, false) }
@@ -86,7 +94,7 @@ impl IsolatedAlloc {
 
     /// Same as `alloc`, but zeroes out the memory.
     ///
-    /// SAFETY: See `alloc::alloc_zeroed()`
+    /// SAFETY: See `alloc::alloc_zeroed()`.
     pub unsafe fn alloc_zeroed(&mut self, layout: Layout) -> *mut u8 {
         // SAFETY: Upheld by caller
         unsafe { self.allocate(layout, true) }
@@ -95,14 +103,13 @@ impl IsolatedAlloc {
     /// Abstracts over the logic of `alloc_zeroed` vs `alloc`, as determined by
     /// the `zeroed` argument.
     ///
-    /// SAFETY: See `alloc::alloc()`, with the added restriction that `page_size`
-    /// corresponds to the host pagesize.
+    /// SAFETY: See `alloc::alloc()`.
     unsafe fn allocate(&mut self, layout: Layout, zeroed: bool) -> *mut u8 {
         let layout = IsolatedAlloc::normalized_layout(layout);
         if self.is_huge_alloc(&layout) {
             // SAFETY: Validity of `layout` upheld by caller; we checked that
             // the size and alignment are appropriate for being a huge alloc
-            unsafe { self.alloc_huge(layout, zeroed) }
+            unsafe { self.alloc_huge(layout) }
         } else {
             for (&mut page, pinfo) in std::iter::zip(&mut self.page_ptrs, &mut self.page_infos) {
                 // SAFETY: The value in `self.page_size` is used to allocate
@@ -132,7 +139,7 @@ impl IsolatedAlloc {
     unsafe fn alloc_small(
         page_size: usize,
         layout: Layout,
-        page: *mut u8,
+        page: NonNull<u8>,
         pinfo: &mut DenseBitSet<usize>,
         zeroed: bool,
     ) -> Option<*mut u8> {
@@ -159,7 +166,7 @@ impl IsolatedAlloc {
                         // zero out, even if we allocated more
                         ptr.write_bytes(0, layout.size());
                     }
-                    return Some(ptr);
+                    return Some(ptr.as_ptr());
                 }
             }
         }
@@ -167,26 +174,50 @@ impl IsolatedAlloc {
     }
 
     /// Expands the available memory pool by adding one page.
-    fn add_page(&mut self) -> (*mut u8, &mut DenseBitSet<usize>) {
-        // SAFETY: The system page size, which is the layout size, cannot be 0
-        let page_ptr = unsafe { alloc::alloc(self.page_layout()) };
+    fn add_page(&mut self) -> (NonNull<u8>, &mut DenseBitSet<usize>) {
+        // SAFETY: mmap is always safe to call when requesting anonymous memory
+        let page_ptr = unsafe {
+            libc::mmap(
+                std::ptr::null_mut(),
+                self.page_size,
+                libc::PROT_READ | libc::PROT_WRITE,
+                libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
+                -1,
+                0,
+            )
+            .cast::<u8>()
+        };
+        assert_ne!(page_ptr.addr(), usize::MAX, "mmap failed");
         // `page_infos` has to have one bit for each `COMPRESSION_FACTOR`-sized chunk of bytes in the page.
-        assert!(self.page_size % COMPRESSION_FACTOR == 0);
+        assert!(self.page_size.is_multiple_of(COMPRESSION_FACTOR));
         self.page_infos.push(DenseBitSet::new_empty(self.page_size / COMPRESSION_FACTOR));
-        self.page_ptrs.push(page_ptr);
-        (page_ptr, self.page_infos.last_mut().unwrap())
+        self.page_ptrs.push(NonNull::new(page_ptr).unwrap());
+        (NonNull::new(page_ptr).unwrap(), self.page_infos.last_mut().unwrap())
     }
 
     /// Allocates in multiples of one page on the host system.
+    /// Will always be zeroed.
     ///
     /// SAFETY: Same as `alloc()`.
-    unsafe fn alloc_huge(&mut self, layout: Layout, zeroed: bool) -> *mut u8 {
-        let layout = IsolatedAlloc::huge_normalized_layout(layout, self.page_size);
-        // SAFETY: Upheld by caller
-        let ret =
-            unsafe { if zeroed { alloc::alloc_zeroed(layout) } else { alloc::alloc(layout) } };
-        self.huge_ptrs.push((ret, layout.size()));
-        ret
+    unsafe fn alloc_huge(&mut self, layout: Layout) -> *mut u8 {
+        let size = self.huge_normalized_layout(layout);
+        // SAFETY: mmap is always safe to call when requesting anonymous memory
+        let ret = unsafe {
+            libc::mmap(
+                std::ptr::null_mut(),
+                size,
+                libc::PROT_READ | libc::PROT_WRITE,
+                libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
+                -1,
+                0,
+            )
+            .cast::<u8>()
+        };
+        assert_ne!(ret.addr(), usize::MAX, "mmap failed");
+        self.huge_ptrs.push((NonNull::new(ret).unwrap(), size));
+        // huge_normalized_layout ensures that we've overallocated enough space
+        // for this to be valid.
+        ret.map_addr(|a| a.next_multiple_of(layout.align()))
     }
 
     /// Deallocates a pointer from this allocator.
@@ -215,15 +246,15 @@ impl IsolatedAlloc {
                 let page_ptr = self.page_ptrs.remove(idx);
                 // SAFETY: We checked that there are no outstanding allocations
                 // from us pointing to this page, and we know it was allocated
-                // with this layout
+                // in add_page as exactly a single page.
                 unsafe {
-                    alloc::dealloc(page_ptr, self.page_layout());
+                    assert_eq!(libc::munmap(page_ptr.as_ptr().cast(), self.page_size), 0);
                 }
             }
         }
     }
 
-    /// Returns the index of the page that this was deallocated from
+    /// Returns the index of the page that this was deallocated from.
     ///
     /// SAFETY: the pointer must have been allocated with `alloc_small`.
     unsafe fn dealloc_small(&mut self, ptr: *mut u8, layout: Layout) -> usize {
@@ -236,7 +267,7 @@ impl IsolatedAlloc {
         // This could be made faster if the list was sorted -- the allocator isn't fully optimized at the moment.
         let pinfo = std::iter::zip(&mut self.page_ptrs, &mut self.page_infos)
             .enumerate()
-            .find(|(_, (page, _))| page.addr() == page_addr);
+            .find(|(_, (page, _))| page.addr().get() == page_addr);
         let Some((idx_of_pinfo, (_, pinfo))) = pinfo else {
             panic!("Freeing in an unallocated page: {ptr:?}\nHolding pages {:?}", self.page_ptrs)
         };
@@ -252,19 +283,72 @@ impl IsolatedAlloc {
     /// SAFETY: Same as `dealloc()` with the added requirement that `layout`
     /// must ask for a size larger than the host pagesize.
     unsafe fn dealloc_huge(&mut self, ptr: *mut u8, layout: Layout) {
-        let layout = IsolatedAlloc::huge_normalized_layout(layout, self.page_size);
-        // Find the pointer matching in address with the one we got
+        let size = self.huge_normalized_layout(layout);
+        // Find the huge allocation containing `ptr`.
         let idx = self
             .huge_ptrs
             .iter()
-            .position(|pg| ptr.addr() == pg.0.addr())
+            .position(|&(pg, size)| {
+                pg.addr().get() <= ptr.addr() && ptr.addr() < pg.addr().get().strict_add(size)
+            })
             .expect("Freeing unallocated pages");
         // And kick it from the list
-        self.huge_ptrs.remove(idx);
-        // SAFETY: Caller ensures validity of the layout
+        let (un_offset_ptr, size2) = self.huge_ptrs.remove(idx);
+        assert_eq!(size, size2, "got wrong layout in dealloc");
+        // SAFETY: huge_ptrs contains allocations made with mmap with the size recorded there.
         unsafe {
-            alloc::dealloc(ptr, layout);
+            let ret = libc::munmap(un_offset_ptr.as_ptr().cast(), size);
+            assert_eq!(ret, 0);
+        }
+    }
+
+    /// Returns a vector of page addresses managed by the allocator.
+    pub fn pages(&self) -> Vec<usize> {
+        let mut pages: Vec<usize> =
+            self.page_ptrs.iter().map(|p| p.expose_provenance().get()).collect();
+        for (ptr, size) in self.huge_ptrs.iter() {
+            for i in 0..size / self.page_size {
+                pages.push(ptr.expose_provenance().get().strict_add(i * self.page_size));
+            }
+        }
+        pages
+    }
+
+    /// Protects all owned memory as `PROT_NONE`, preventing accesses.
+    ///
+    /// SAFETY: Accessing memory after this point will result in a segfault
+    /// unless it is first unprotected.
+    pub unsafe fn prepare_ffi(&mut self) -> Result<(), nix::errno::Errno> {
+        let prot = mman::ProtFlags::PROT_NONE;
+        unsafe { self.mprotect(prot) }
+    }
+
+    /// Deprotects all owned memory by setting it to RW. Erroring here is very
+    /// likely unrecoverable, so it may panic if applying those permissions
+    /// fails.
+    pub fn unprep_ffi(&mut self) {
+        let prot = mman::ProtFlags::PROT_READ | mman::ProtFlags::PROT_WRITE;
+        unsafe {
+            self.mprotect(prot).unwrap();
+        }
+    }
+
+    /// Applies `prot` to every page managed by the allocator.
+    ///
+    /// SAFETY: Accessing memory in violation of the protection flags will
+    /// trigger a segfault.
+    unsafe fn mprotect(&mut self, prot: mman::ProtFlags) -> Result<(), nix::errno::Errno> {
+        for &pg in &self.page_ptrs {
+            unsafe {
+                mman::mprotect(pg.cast(), self.page_size, prot)?;
+            }
+        }
+        for &(hpg, size) in &self.huge_ptrs {
+            unsafe {
+                mman::mprotect(hpg.cast(), size.next_multiple_of(self.page_size), prot)?;
+            }
         }
+        Ok(())
     }
 }
 
@@ -347,12 +431,15 @@ mod tests {
         sizes.append(&mut vec![256; 12]);
         // Give it some multi-page ones too
         sizes.append(&mut vec![32 * 1024; 4]);
+        sizes.push(4 * 1024);
 
         // Matching aligns for the sizes
         let mut aligns = vec![16; 12];
         aligns.append(&mut vec![256; 2]);
         aligns.append(&mut vec![64; 12]);
         aligns.append(&mut vec![4096; 4]);
+        // And one that requests align > page_size
+        aligns.push(64 * 1024);
 
         // Make sure we didn't mess up in the test itself!
         assert_eq!(sizes.len(), aligns.len());
diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs
index 4a038fe6487..3cc38fa087c 100644
--- a/src/tools/miri/src/alloc_addresses/mod.rs
+++ b/src/tools/miri/src/alloc_addresses/mod.rs
@@ -390,7 +390,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx, interpret::Pointer<Provenance>> {
         let this = self.eval_context_ref();
 
-        let (prov, offset) = ptr.into_parts(); // offset is relative (AllocId provenance)
+        let (prov, offset) = ptr.prov_and_relative_offset();
         let alloc_id = prov.alloc_id();
 
         // Get a pointer to the beginning of this allocation.
@@ -447,7 +447,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> Option<(AllocId, Size)> {
         let this = self.eval_context_ref();
 
-        let (tag, addr) = ptr.into_parts(); // addr is absolute (Tag provenance)
+        let (tag, addr) = ptr.into_raw_parts(); // addr is absolute (Miri provenance)
 
         let alloc_id = if let Provenance::Concrete { alloc_id, .. } = tag {
             alloc_id
@@ -466,17 +466,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         Some((alloc_id, Size::from_bytes(rel_offset)))
     }
 
-    /// Prepare all exposed memory for a native call.
-    /// This overapproximates the modifications which external code might make to memory:
-    /// We set all reachable allocations as initialized, mark all reachable provenances as exposed
-    /// and overwrite them with `Provenance::WILDCARD`.
-    fn prepare_exposed_for_native_call(&mut self) -> InterpResult<'tcx> {
-        let this = self.eval_context_mut();
-        // We need to make a deep copy of this list, but it's fine; it also serves as scratch space
-        // for the search within `prepare_for_native_call`.
-        let exposed: Vec<AllocId> =
-            this.machine.alloc_addresses.get_mut().exposed.iter().copied().collect();
-        this.prepare_for_native_call(exposed)
+    /// Return a list of all exposed allocations.
+    fn exposed_allocs(&self) -> Vec<AllocId> {
+        let this = self.eval_context_ref();
+        this.machine.alloc_addresses.borrow().exposed.iter().copied().collect()
     }
 }
 
diff --git a/src/tools/miri/src/alloc_addresses/reuse_pool.rs b/src/tools/miri/src/alloc_addresses/reuse_pool.rs
index ab6aaed5e3e..b6cc017f772 100644
--- a/src/tools/miri/src/alloc_addresses/reuse_pool.rs
+++ b/src/tools/miri/src/alloc_addresses/reuse_pool.rs
@@ -129,7 +129,7 @@ impl ReusePool {
         let idx = rng.random_range(begin..end);
         // Remove it from the pool and return.
         let (chosen_addr, chosen_size, chosen_thread, clock) = subpool.remove(idx);
-        debug_assert!(chosen_size >= size && chosen_addr % align.bytes() == 0);
+        debug_assert!(chosen_size >= size && chosen_addr.is_multiple_of(align.bytes()));
         debug_assert!(cross_thread_reuse || chosen_thread == thread);
         // No synchronization needed if we reused from the current thread.
         Some((chosen_addr, if chosen_thread == thread { None } else { Some(clock) }))
diff --git a/src/tools/miri/src/bin/log/mod.rs b/src/tools/miri/src/bin/log/mod.rs
new file mode 100644
index 00000000000..f3b2fdb5348
--- /dev/null
+++ b/src/tools/miri/src/bin/log/mod.rs
@@ -0,0 +1,2 @@
+pub mod setup;
+mod tracing_chrome;
diff --git a/src/tools/miri/src/bin/log/setup.rs b/src/tools/miri/src/bin/log/setup.rs
new file mode 100644
index 00000000000..da0ba528b2c
--- /dev/null
+++ b/src/tools/miri/src/bin/log/setup.rs
@@ -0,0 +1,126 @@
+use std::env::{self, VarError};
+use std::str::FromStr;
+use std::sync::{Mutex, OnceLock};
+
+use rustc_middle::ty::TyCtxt;
+use rustc_session::{CtfeBacktrace, EarlyDiagCtxt};
+
+/// The tracing layer from `tracing-chrome` starts a thread in the background that saves data to
+/// file and closes the file when stopped. If the thread is not stopped properly, the file will be
+/// missing end terminators (`]` for JSON arrays) and other data may also not be flushed. Therefore
+/// we need to keep a guard that, when [Drop]ped, will send a signal to stop the thread. Make sure
+/// to manually drop this guard using [deinit_loggers], if you are exiting the program with
+/// [std::process::exit]!
+#[must_use]
+struct TracingGuard {
+    #[cfg(feature = "tracing")]
+    _chrome: super::tracing_chrome::FlushGuard,
+    _no_construct: (),
+}
+
+// This ensures TracingGuard is always a drop-type, even when the `_chrome` field is disabled.
+impl Drop for TracingGuard {
+    fn drop(&mut self) {}
+}
+
+fn rustc_logger_config() -> rustc_log::LoggerConfig {
+    // Start with the usual env vars.
+    let mut cfg = rustc_log::LoggerConfig::from_env("RUSTC_LOG");
+
+    // Overwrite if MIRI_LOG is set.
+    if let Ok(var) = env::var("MIRI_LOG") {
+        // MIRI_LOG serves as default for RUSTC_LOG, if that is not set.
+        if matches!(cfg.filter, Err(VarError::NotPresent)) {
+            // We try to be a bit clever here: if `MIRI_LOG` is just a single level
+            // used for everything, we only apply it to the parts of rustc that are
+            // CTFE-related. Otherwise, we use it verbatim for `RUSTC_LOG`.
+            // This way, if you set `MIRI_LOG=trace`, you get only the right parts of
+            // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_const_eval::interpret=debug`.
+            if tracing::Level::from_str(&var).is_ok() {
+                cfg.filter = Ok(format!(
+                    "rustc_middle::mir::interpret={var},rustc_const_eval::interpret={var},miri={var}"
+                ));
+            } else {
+                cfg.filter = Ok(var);
+            }
+        }
+    }
+
+    cfg
+}
+
+/// The global logger can only be set once per process, so track whether that already happened and
+/// keep a [TracingGuard] so it can be [Drop]ped later using [deinit_loggers].
+static LOGGER_INITED: OnceLock<Mutex<Option<TracingGuard>>> = OnceLock::new();
+
+fn init_logger_once(early_dcx: &EarlyDiagCtxt) {
+    // If the logger is not yet initialized, initialize it.
+    LOGGER_INITED.get_or_init(|| {
+        let guard = if env::var_os("MIRI_TRACING").is_some() {
+            #[cfg(not(feature = "tracing"))]
+            {
+                crate::fatal_error!(
+                    "fatal error: cannot enable MIRI_TRACING since Miri was not built with the \"tracing\" feature"
+                );
+            }
+
+            #[cfg(feature = "tracing")]
+            {
+                let (chrome_layer, chrome_guard) =
+                    super::tracing_chrome::ChromeLayerBuilder::new().include_args(true).build();
+                rustc_driver::init_logger_with_additional_layer(
+                    early_dcx,
+                    rustc_logger_config(),
+                    || {
+                        tracing_subscriber::layer::SubscriberExt::with(
+                            tracing_subscriber::Registry::default(),
+                            chrome_layer,
+                        )
+                    },
+                );
+
+                Some(TracingGuard { _chrome: chrome_guard, _no_construct: () })
+            }
+        } else {
+            // initialize the logger without any tracing enabled
+            rustc_driver::init_logger(early_dcx, rustc_logger_config());
+            None
+        };
+        Mutex::new(guard)
+    });
+}
+
+pub fn init_early_loggers(early_dcx: &EarlyDiagCtxt) {
+    // We only initialize `rustc` if the env var is set (so the user asked for it).
+    // If it is not set, we avoid initializing now so that we can initialize later with our custom
+    // settings, and *not* log anything for what happens before `miri` starts interpreting.
+    if env::var_os("RUSTC_LOG").is_some() {
+        init_logger_once(early_dcx);
+    }
+}
+
+pub fn init_late_loggers(early_dcx: &EarlyDiagCtxt, tcx: TyCtxt<'_>) {
+    // If the logger is not yet initialized, initialize it.
+    init_logger_once(early_dcx);
+
+    // If `MIRI_BACKTRACE` is set and `RUSTC_CTFE_BACKTRACE` is not, set `RUSTC_CTFE_BACKTRACE`.
+    // Do this late, so we ideally only apply this to Miri's errors.
+    if let Some(val) = env::var_os("MIRI_BACKTRACE") {
+        let ctfe_backtrace = match &*val.to_string_lossy() {
+            "immediate" => CtfeBacktrace::Immediate,
+            "0" => CtfeBacktrace::Disabled,
+            _ => CtfeBacktrace::Capture,
+        };
+        *tcx.sess.ctfe_backtrace.borrow_mut() = ctfe_backtrace;
+    }
+}
+
+/// Must be called before the program terminates to ensure the trace file is closed correctly. Not
+/// doing so will result in invalid trace files. Also see [TracingGuard].
+pub fn deinit_loggers() {
+    if let Some(guard) = LOGGER_INITED.get()
+        && let Ok(mut guard) = guard.lock()
+    {
+        std::mem::drop(guard.take());
+    }
+}
diff --git a/src/tools/miri/src/bin/log/tracing_chrome.rs b/src/tools/miri/src/bin/log/tracing_chrome.rs
new file mode 100644
index 00000000000..459acea6f0b
--- /dev/null
+++ b/src/tools/miri/src/bin/log/tracing_chrome.rs
@@ -0,0 +1,625 @@
+// SPDX-License-Identifier: MIT
+// SPDX-FileCopyrightText: Copyright (c) 2020 Thoren Paulson
+//! This file is taken unmodified from the following link, except for file attributes and
+//! `extern crate` at the top.
+//! https://github.com/thoren-d/tracing-chrome/blob/7e2625ab4aeeef2f0ef9bde9d6258dd181c04472/src/lib.rs
+//! Depending on the tracing-chrome crate from crates.io is unfortunately not possible, since it
+//! depends on `tracing_core` which conflicts with rustc_private's `tracing_core` (meaning it would
+//! not be possible to use the [ChromeLayer] in a context that expects a [Layer] from
+//! rustc_private's `tracing_core` version).
+#![allow(warnings)]
+#![cfg(feature = "tracing")]
+
+// This is here and not in src/lib.rs since it is a direct dependency of tracing_chrome.rs and
+// should not be included if the "tracing" feature is disabled.
+extern crate tracing_core;
+
+use tracing_core::{field::Field, span, Event, Subscriber};
+use tracing_subscriber::{
+    layer::Context,
+    registry::{LookupSpan, SpanRef},
+    Layer,
+};
+
+use serde_json::{json, Value as JsonValue};
+use std::{
+    marker::PhantomData,
+    path::Path,
+    sync::{
+        atomic::{AtomicUsize, Ordering},
+        Arc, Mutex,
+    },
+};
+
+use std::io::{BufWriter, Write};
+use std::sync::mpsc;
+use std::sync::mpsc::Sender;
+use std::{
+    cell::{Cell, RefCell},
+    thread::JoinHandle,
+};
+
+thread_local! {
+    static OUT: RefCell<Option<Sender<Message>>> = const { RefCell::new(None) };
+    static TID: RefCell<Option<usize>> = const { RefCell::new(None) };
+}
+
+type NameFn<S> = Box<dyn Fn(&EventOrSpan<'_, '_, S>) -> String + Send + Sync>;
+type Object = serde_json::Map<String, JsonValue>;
+
+/// A [`Layer`](tracing_subscriber::Layer) that writes a Chrome trace file.
+pub struct ChromeLayer<S>
+where
+    S: Subscriber + for<'span> LookupSpan<'span> + Send + Sync,
+{
+    out: Arc<Mutex<Sender<Message>>>,
+    start: std::time::Instant,
+    max_tid: AtomicUsize,
+    include_args: bool,
+    include_locations: bool,
+    trace_style: TraceStyle,
+    name_fn: Option<NameFn<S>>,
+    cat_fn: Option<NameFn<S>>,
+    _inner: PhantomData<S>,
+}
+
+/// A builder for [`ChromeLayer`](crate::ChromeLayer).
+#[derive(Default)]
+pub struct ChromeLayerBuilder<S>
+where
+    S: Subscriber + for<'span> LookupSpan<'span> + Send + Sync,
+{
+    out_writer: Option<Box<dyn Write + Send>>,
+    name_fn: Option<NameFn<S>>,
+    cat_fn: Option<NameFn<S>>,
+    include_args: bool,
+    include_locations: bool,
+    trace_style: TraceStyle,
+    _inner: PhantomData<S>,
+}
+
+/// Decides how traces will be recorded.
+#[derive(Default)]
+pub enum TraceStyle {
+    /// Traces will be recorded as a group of threads.
+    /// In this style, spans should be entered and exited on the same thread.
+    #[default]
+    Threaded,
+
+    /// Traces will recorded as a group of asynchronous operations.
+    Async,
+}
+
+impl<S> ChromeLayerBuilder<S>
+where
+    S: Subscriber + for<'span> LookupSpan<'span> + Send + Sync,
+{
+    pub fn new() -> Self {
+        ChromeLayerBuilder {
+            out_writer: None,
+            name_fn: None,
+            cat_fn: None,
+            include_args: false,
+            include_locations: true,
+            trace_style: TraceStyle::Threaded,
+            _inner: PhantomData,
+        }
+    }
+
+    /// Set the file to which to output the trace.
+    ///
+    /// Defaults to `./trace-{unix epoch in micros}.json`.
+    ///
+    /// # Panics
+    ///
+    /// If `file` could not be opened/created. To handle errors,
+    /// open a file and pass it to [`writer`](crate::ChromeLayerBuilder::writer) instead.
+    pub fn file<P: AsRef<Path>>(self, file: P) -> Self {
+        self.writer(std::fs::File::create(file).expect("Failed to create trace file."))
+    }
+
+    /// Supply an arbitrary writer to which to write trace contents.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// # use tracing_chrome::ChromeLayerBuilder;
+    /// # use tracing_subscriber::prelude::*;
+    /// let (layer, guard) = ChromeLayerBuilder::new().writer(std::io::sink()).build();
+    /// # tracing_subscriber::registry().with(layer).init();
+    /// ```
+    pub fn writer<W: Write + Send + 'static>(mut self, writer: W) -> Self {
+        self.out_writer = Some(Box::new(writer));
+        self
+    }
+
+    /// Include arguments in each trace entry.
+    ///
+    /// Defaults to `false`.
+    ///
+    /// Includes the arguments used when creating a span/event
+    /// in the "args" section of the trace entry.
+    pub fn include_args(mut self, include: bool) -> Self {
+        self.include_args = include;
+        self
+    }
+
+    /// Include file+line with each trace entry.
+    ///
+    /// Defaults to `true`.
+    ///
+    /// This can add quite a bit of data to the output so turning
+    /// it off might be helpful when collecting larger traces.
+    pub fn include_locations(mut self, include: bool) -> Self {
+        self.include_locations = include;
+        self
+    }
+
+    /// Sets the style used when recording trace events.
+    ///
+    /// See [`TraceStyle`](crate::TraceStyle) for details.
+    pub fn trace_style(mut self, style: TraceStyle) -> Self {
+        self.trace_style = style;
+        self
+    }
+
+    /// Allows supplying a function that derives a name from
+    /// an Event or Span. The result is used as the "name" field
+    /// on trace entries.
+    ///
+    /// # Example
+    /// ```
+    /// use tracing_chrome::{ChromeLayerBuilder, EventOrSpan};
+    /// use tracing_subscriber::{registry::Registry, prelude::*};
+    ///
+    /// let (chrome_layer, _guard) = ChromeLayerBuilder::new().name_fn(Box::new(|event_or_span| {
+    ///     match event_or_span {
+    ///         EventOrSpan::Event(ev) => { ev.metadata().name().into() },
+    ///         EventOrSpan::Span(_s) => { "span".into() },
+    ///     }
+    /// })).build();
+    /// tracing_subscriber::registry().with(chrome_layer).init()
+    /// ```
+    pub fn name_fn(mut self, name_fn: NameFn<S>) -> Self {
+        self.name_fn = Some(name_fn);
+        self
+    }
+
+    /// Allows supplying a function that derives a category from
+    /// an Event or Span. The result is used as the "cat" field on
+    /// trace entries.
+    ///
+    /// # Example
+    /// ```
+    /// use tracing_chrome::{ChromeLayerBuilder, EventOrSpan};
+    /// use tracing_subscriber::{registry::Registry, prelude::*};
+    ///
+    /// let (chrome_layer, _guard) = ChromeLayerBuilder::new().category_fn(Box::new(|_| {
+    ///     "my_module".into()
+    /// })).build();
+    /// tracing_subscriber::registry().with(chrome_layer).init()
+    /// ```
+    pub fn category_fn(mut self, cat_fn: NameFn<S>) -> Self {
+        self.cat_fn = Some(cat_fn);
+        self
+    }
+
+    /// Creates a [`ChromeLayer`](crate::ChromeLayer) and associated [`FlushGuard`](crate::FlushGuard).
+    ///
+    /// # Panics
+    ///
+    /// If no file or writer was specified and the default trace file could not be opened/created.
+    pub fn build(self) -> (ChromeLayer<S>, FlushGuard) {
+        ChromeLayer::new(self)
+    }
+}
+
+/// This guard will signal the thread writing the trace file to stop and join it when dropped.
+pub struct FlushGuard {
+    sender: Sender<Message>,
+    handle: Cell<Option<JoinHandle<()>>>,
+}
+
+impl FlushGuard {
+    /// Signals the trace writing thread to flush to disk.
+    pub fn flush(&self) {
+        if let Some(handle) = self.handle.take() {
+            let _ignored = self.sender.send(Message::Flush);
+            self.handle.set(Some(handle));
+        }
+    }
+
+    /// Finishes the current trace and starts a new one.
+    ///
+    /// If a [`Write`](std::io::Write) implementation is supplied,
+    /// the new trace is written to it. Otherwise, the new trace
+    /// goes to `./trace-{unix epoc in micros}.json`.
+    pub fn start_new(&self, writer: Option<Box<dyn Write + Send>>) {
+        if let Some(handle) = self.handle.take() {
+            let _ignored = self.sender.send(Message::StartNew(writer));
+            self.handle.set(Some(handle));
+        }
+    }
+}
+
+impl Drop for FlushGuard {
+    fn drop(&mut self) {
+        if let Some(handle) = self.handle.take() {
+            let _ignored = self.sender.send(Message::Drop);
+            if handle.join().is_err() {
+                eprintln!("tracing_chrome: Trace writing thread panicked.");
+            }
+        }
+    }
+}
+
+struct Callsite {
+    tid: usize,
+    name: String,
+    target: String,
+    file: Option<&'static str>,
+    line: Option<u32>,
+    args: Option<Arc<Object>>,
+}
+
+enum Message {
+    Enter(f64, Callsite, Option<u64>),
+    Event(f64, Callsite),
+    Exit(f64, Callsite, Option<u64>),
+    NewThread(usize, String),
+    Flush,
+    Drop,
+    StartNew(Option<Box<dyn Write + Send>>),
+}
+
+/// Represents either an [`Event`](tracing_core::Event) or [`SpanRef`](tracing_subscriber::registry::SpanRef).
+pub enum EventOrSpan<'a, 'b, S>
+where
+    S: Subscriber + for<'span> LookupSpan<'span> + Send + Sync,
+{
+    Event(&'a Event<'b>),
+    Span(&'a SpanRef<'b, S>),
+}
+
+fn create_default_writer() -> Box<dyn Write + Send> {
+    Box::new(
+        std::fs::File::create(format!(
+            "./trace-{}.json",
+            std::time::SystemTime::UNIX_EPOCH
+                .elapsed()
+                .unwrap()
+                .as_micros()
+        ))
+        .expect("Failed to create trace file."),
+    )
+}
+
+impl<S> ChromeLayer<S>
+where
+    S: Subscriber + for<'span> LookupSpan<'span> + Send + Sync,
+{
+    fn new(mut builder: ChromeLayerBuilder<S>) -> (ChromeLayer<S>, FlushGuard) {
+        let (tx, rx) = mpsc::channel();
+        OUT.with(|val| val.replace(Some(tx.clone())));
+
+        let out_writer = builder
+            .out_writer
+            .unwrap_or_else(|| create_default_writer());
+
+        let handle = std::thread::spawn(move || {
+            let mut write = BufWriter::new(out_writer);
+            write.write_all(b"[\n").unwrap();
+
+            let mut has_started = false;
+            let mut thread_names: Vec<(usize, String)> = Vec::new();
+            for msg in rx {
+                if let Message::Flush = &msg {
+                    write.flush().unwrap();
+                    continue;
+                } else if let Message::Drop = &msg {
+                    break;
+                } else if let Message::StartNew(writer) = msg {
+                    // Finish off current file
+                    write.write_all(b"\n]").unwrap();
+                    write.flush().unwrap();
+
+                    // Get or create new writer
+                    let out_writer = writer.unwrap_or_else(|| create_default_writer());
+                    write = BufWriter::new(out_writer);
+                    write.write_all(b"[\n").unwrap();
+                    has_started = false;
+
+                    // Write saved thread names
+                    for (tid, name) in thread_names.iter() {
+                        let entry = json!({
+                            "ph": "M",
+                            "pid": 1,
+                            "name": "thread_name",
+                            "tid": *tid,
+                            "args": {
+                                "name": name,
+                            },
+                        });
+
+                        if has_started {
+                            write.write_all(b",\n").unwrap();
+                        }
+                        serde_json::to_writer(&mut write, &entry).unwrap();
+                        has_started = true;
+                    }
+                    continue;
+                }
+
+                let (ph, ts, callsite, id) = match &msg {
+                    Message::Enter(ts, callsite, None) => ("B", Some(ts), Some(callsite), None),
+                    Message::Enter(ts, callsite, Some(root_id)) => {
+                        ("b", Some(ts), Some(callsite), Some(root_id))
+                    }
+                    Message::Event(ts, callsite) => ("i", Some(ts), Some(callsite), None),
+                    Message::Exit(ts, callsite, None) => ("E", Some(ts), Some(callsite), None),
+                    Message::Exit(ts, callsite, Some(root_id)) => {
+                        ("e", Some(ts), Some(callsite), Some(root_id))
+                    }
+                    Message::NewThread(_tid, _name) => ("M", None, None, None),
+                    Message::Flush | Message::Drop | Message::StartNew(_) => {
+                        panic!("Was supposed to break by now.")
+                    }
+                };
+                let mut entry = json!({
+                    "ph": ph,
+                    "pid": 1,
+                });
+
+                if let Message::NewThread(tid, name) = msg {
+                    thread_names.push((tid, name.clone()));
+                    entry["name"] = "thread_name".into();
+                    entry["tid"] = tid.into();
+                    entry["args"] = json!({ "name": name });
+                } else {
+                    let ts = ts.unwrap();
+                    let callsite = callsite.unwrap();
+                    entry["ts"] = (*ts).into();
+                    entry["name"] = callsite.name.clone().into();
+                    entry["cat"] = callsite.target.clone().into();
+                    entry["tid"] = callsite.tid.into();
+
+                    if let Some(&id) = id {
+                        entry["id"] = id.into();
+                    }
+
+                    if ph == "i" {
+                        entry["s"] = "t".into();
+                    }
+
+                    if let (Some(file), Some(line)) = (callsite.file, callsite.line) {
+                        entry[".file"] = file.into();
+                        entry[".line"] = line.into();
+                    }
+
+                    if let Some(call_args) = &callsite.args {
+                        if !call_args.is_empty() {
+                            entry["args"] = (**call_args).clone().into();
+                        }
+                    }
+                }
+
+                if has_started {
+                    write.write_all(b",\n").unwrap();
+                }
+                serde_json::to_writer(&mut write, &entry).unwrap();
+                has_started = true;
+            }
+
+            write.write_all(b"\n]").unwrap();
+            write.flush().unwrap();
+        });
+
+        let guard = FlushGuard {
+            sender: tx.clone(),
+            handle: Cell::new(Some(handle)),
+        };
+        let layer = ChromeLayer {
+            out: Arc::new(Mutex::new(tx)),
+            start: std::time::Instant::now(),
+            max_tid: AtomicUsize::new(0),
+            name_fn: builder.name_fn.take(),
+            cat_fn: builder.cat_fn.take(),
+            include_args: builder.include_args,
+            include_locations: builder.include_locations,
+            trace_style: builder.trace_style,
+            _inner: PhantomData,
+        };
+
+        (layer, guard)
+    }
+
+    fn get_tid(&self) -> (usize, bool) {
+        TID.with(|value| {
+            let tid = *value.borrow();
+            match tid {
+                Some(tid) => (tid, false),
+                None => {
+                    let tid = self.max_tid.fetch_add(1, Ordering::SeqCst);
+                    value.replace(Some(tid));
+                    (tid, true)
+                }
+            }
+        })
+    }
+
+    fn get_callsite(&self, data: EventOrSpan<S>) -> Callsite {
+        let (tid, new_thread) = self.get_tid();
+        let name = self.name_fn.as_ref().map(|name_fn| name_fn(&data));
+        let target = self.cat_fn.as_ref().map(|cat_fn| cat_fn(&data));
+        let meta = match data {
+            EventOrSpan::Event(e) => e.metadata(),
+            EventOrSpan::Span(s) => s.metadata(),
+        };
+        let args = match data {
+            EventOrSpan::Event(e) => {
+                if self.include_args {
+                    let mut args = Object::new();
+                    e.record(&mut JsonVisitor { object: &mut args });
+                    Some(Arc::new(args))
+                } else {
+                    None
+                }
+            }
+            EventOrSpan::Span(s) => s
+                .extensions()
+                .get::<ArgsWrapper>()
+                .map(|e| &e.args)
+                .cloned(),
+        };
+        let name = name.unwrap_or_else(|| meta.name().into());
+        let target = target.unwrap_or_else(|| meta.target().into());
+        let (file, line) = if self.include_locations {
+            (meta.file(), meta.line())
+        } else {
+            (None, None)
+        };
+
+        if new_thread {
+            let name = match std::thread::current().name() {
+                Some(name) => name.to_owned(),
+                None => tid.to_string(),
+            };
+            self.send_message(Message::NewThread(tid, name));
+        }
+
+        Callsite {
+            tid,
+            name,
+            target,
+            file,
+            line,
+            args,
+        }
+    }
+
+    fn get_root_id(span: SpanRef<S>) -> u64 {
+        span.scope()
+            .from_root()
+            .take(1)
+            .next()
+            .unwrap_or(span)
+            .id()
+            .into_u64()
+    }
+
+    fn enter_span(&self, span: SpanRef<S>, ts: f64) {
+        let callsite = self.get_callsite(EventOrSpan::Span(&span));
+        let root_id = match self.trace_style {
+            TraceStyle::Async => Some(ChromeLayer::get_root_id(span)),
+            _ => None,
+        };
+        self.send_message(Message::Enter(ts, callsite, root_id));
+    }
+
+    fn exit_span(&self, span: SpanRef<S>, ts: f64) {
+        let callsite = self.get_callsite(EventOrSpan::Span(&span));
+        let root_id = match self.trace_style {
+            TraceStyle::Async => Some(ChromeLayer::get_root_id(span)),
+            _ => None,
+        };
+        self.send_message(Message::Exit(ts, callsite, root_id));
+    }
+
+    fn get_ts(&self) -> f64 {
+        self.start.elapsed().as_nanos() as f64 / 1000.0
+    }
+
+    fn send_message(&self, message: Message) {
+        OUT.with(move |val| {
+            if val.borrow().is_some() {
+                let _ignored = val.borrow().as_ref().unwrap().send(message);
+            } else {
+                let out = self.out.lock().unwrap().clone();
+                let _ignored = out.send(message);
+                val.replace(Some(out));
+            }
+        });
+    }
+}
+
+impl<S> Layer<S> for ChromeLayer<S>
+where
+    S: Subscriber + for<'span> LookupSpan<'span> + Send + Sync,
+{
+    fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) {
+        if let TraceStyle::Async = self.trace_style {
+            return;
+        }
+
+        let ts = self.get_ts();
+        self.enter_span(ctx.span(id).expect("Span not found."), ts);
+    }
+
+    fn on_record(&self, id: &span::Id, values: &span::Record<'_>, ctx: Context<'_, S>) {
+        if self.include_args {
+            let span = ctx.span(id).unwrap();
+            let mut exts = span.extensions_mut();
+
+            let args = exts.get_mut::<ArgsWrapper>();
+
+            if let Some(args) = args {
+                let args = Arc::make_mut(&mut args.args);
+                values.record(&mut JsonVisitor { object: args });
+            }
+        }
+    }
+
+    fn on_event(&self, event: &Event<'_>, _ctx: Context<'_, S>) {
+        let ts = self.get_ts();
+        let callsite = self.get_callsite(EventOrSpan::Event(event));
+        self.send_message(Message::Event(ts, callsite));
+    }
+
+    fn on_exit(&self, id: &span::Id, ctx: Context<'_, S>) {
+        if let TraceStyle::Async = self.trace_style {
+            return;
+        }
+        let ts = self.get_ts();
+        self.exit_span(ctx.span(id).expect("Span not found."), ts);
+    }
+
+    fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, S>) {
+        if self.include_args {
+            let mut args = Object::new();
+            attrs.record(&mut JsonVisitor { object: &mut args });
+            ctx.span(id).unwrap().extensions_mut().insert(ArgsWrapper {
+                args: Arc::new(args),
+            });
+        }
+        if let TraceStyle::Threaded = self.trace_style {
+            return;
+        }
+
+        let ts = self.get_ts();
+        self.enter_span(ctx.span(id).expect("Span not found."), ts);
+    }
+
+    fn on_close(&self, id: span::Id, ctx: Context<'_, S>) {
+        if let TraceStyle::Threaded = self.trace_style {
+            return;
+        }
+
+        let ts = self.get_ts();
+        self.exit_span(ctx.span(&id).expect("Span not found."), ts);
+    }
+}
+
+struct JsonVisitor<'a> {
+    object: &'a mut Object,
+}
+
+impl<'a> tracing_subscriber::field::Visit for JsonVisitor<'a> {
+    fn record_debug(&mut self, field: &Field, value: &dyn std::fmt::Debug) {
+        self.object
+            .insert(field.name().to_owned(), format!("{value:?}").into());
+    }
+}
+
+struct ArgsWrapper {
+    args: Arc<Object>,
+}
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 72057f812f9..e3b579a4ac6 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -10,6 +10,8 @@
 
 // Some "regular" crates we want to share with rustc
 extern crate tracing;
+#[cfg(feature = "tracing")]
+extern crate tracing_subscriber;
 
 // The rustc crates we need
 extern crate rustc_abi;
@@ -24,14 +26,16 @@ extern crate rustc_middle;
 extern crate rustc_session;
 extern crate rustc_span;
 
-use std::env::{self, VarError};
+mod log;
+
+use std::env;
 use std::num::NonZero;
 use std::ops::Range;
 use std::path::PathBuf;
 use std::rc::Rc;
 use std::str::FromStr;
+use std::sync::Arc;
 use std::sync::atomic::{AtomicI32, AtomicU32, Ordering};
-use std::sync::{Arc, Once};
 
 use miri::{
     BacktraceStyle, BorrowTrackerMethod, GenmcConfig, GenmcCtx, MiriConfig, MiriEntryFnType,
@@ -52,12 +56,14 @@ 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::EarlyDiagCtxt;
 use rustc_session::config::{CrateType, ErrorOutputType, OptLevel};
 use rustc_session::search_paths::PathKind;
-use rustc_session::{CtfeBacktrace, EarlyDiagCtxt};
 use rustc_span::def_id::DefId;
 use tracing::debug;
 
+use crate::log::setup::{deinit_loggers, init_early_loggers, init_late_loggers};
+
 struct MiriCompilerCalls {
     miri_config: Option<MiriConfig>,
     many_seeds: Option<ManySeedsConfig>,
@@ -85,7 +91,7 @@ fn entry_fn(tcx: TyCtxt<'_>) -> (DefId, MiriEntryFnType) {
         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, _)| {
+    let sym = tcx.exported_non_generic_symbols(LOCAL_CRATE).iter().find_map(|(sym, _)| {
         if sym.symbol_name_for_local_instance(tcx).name == "miri_start" { Some(sym) } else { None }
     });
     if let Some(ExportedSymbol::NonGeneric(id)) = sym {
@@ -154,13 +160,13 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
         if tcx.sess.dcx().has_errors_or_delayed_bugs().is_some() {
             tcx.dcx().fatal("miri cannot be run on programs that fail compilation");
         }
-
-        let early_dcx = EarlyDiagCtxt::new(tcx.sess.opts.error_format);
-        init_late_loggers(&early_dcx, tcx);
         if !tcx.crate_types().contains(&CrateType::Executable) {
             tcx.dcx().fatal("miri only makes sense on bin crates");
         }
 
+        let early_dcx = EarlyDiagCtxt::new(tcx.sess.opts.error_format);
+        init_late_loggers(&early_dcx, tcx);
+
         let (entry_def_id, entry_type) = entry_fn(tcx);
         let mut config = self.miri_config.take().expect("after_analysis must only be called once");
 
@@ -213,7 +219,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
                     if !many_seeds.keep_going {
                         // `abort_if_errors` would actually not stop, since `par_for_each` waits for the
                         // rest of the to finish, so we just exit immediately.
-                        std::process::exit(return_code);
+                        exit(return_code);
                     }
                     exit_code.store(return_code, Ordering::Relaxed);
                     num_failed.fetch_add(1, Ordering::Relaxed);
@@ -223,15 +229,16 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
             if num_failed > 0 {
                 eprintln!("{num_failed}/{total} SEEDS FAILED", total = many_seeds.seeds.count());
             }
-            std::process::exit(exit_code.0.into_inner());
+            exit(exit_code.0.into_inner());
         } else {
             let return_code = miri::eval_entry(tcx, entry_def_id, entry_type, &config, None)
                 .unwrap_or_else(|| {
+                    //#[cfg(target_os = "linux")]
+                    //miri::native_lib::register_retcode_sv(rustc_driver::EXIT_FAILURE);
                     tcx.dcx().abort_if_errors();
                     rustc_driver::EXIT_FAILURE
                 });
-
-            std::process::exit(return_code);
+            exit(return_code);
         }
 
         // Unreachable.
@@ -249,10 +256,10 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
             // Queries overridden here affect the data stored in `rmeta` files of dependencies,
             // which will be used later in non-`MIRI_BE_RUSTC` mode.
             config.override_queries = Some(|_, local_providers| {
-                // `exported_symbols` and `reachable_non_generics` provided by rustc always returns
+                // `exported_non_generic_symbols` and `reachable_non_generics` provided by rustc always returns
                 // an empty result if `tcx.sess.opts.output_types.should_codegen()` is false.
                 // In addition we need to add #[used] symbols to exported_symbols for `lookup_link_section`.
-                local_providers.exported_symbols = |tcx, LocalCrate| {
+                local_providers.exported_non_generic_symbols = |tcx, LocalCrate| {
                     let reachable_set = tcx.with_stable_hashing_context(|hcx| {
                         tcx.reachable_set(()).to_sorted(&hcx, true)
                     });
@@ -327,83 +334,31 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
     }
 }
 
-fn show_error(msg: &impl std::fmt::Display) -> ! {
-    eprintln!("fatal error: {msg}");
-    std::process::exit(1)
+fn exit(exit_code: i32) -> ! {
+    // Drop the tracing guard before exiting, so tracing calls are flushed correctly.
+    deinit_loggers();
+    std::process::exit(exit_code);
 }
 
-macro_rules! show_error {
-    ($($tt:tt)*) => { show_error(&format_args!($($tt)*)) };
-}
-
-fn rustc_logger_config() -> rustc_log::LoggerConfig {
-    // Start with the usual env vars.
-    let mut cfg = rustc_log::LoggerConfig::from_env("RUSTC_LOG");
-
-    // Overwrite if MIRI_LOG is set.
-    if let Ok(var) = env::var("MIRI_LOG") {
-        // MIRI_LOG serves as default for RUSTC_LOG, if that is not set.
-        if matches!(cfg.filter, Err(VarError::NotPresent)) {
-            // We try to be a bit clever here: if `MIRI_LOG` is just a single level
-            // used for everything, we only apply it to the parts of rustc that are
-            // CTFE-related. Otherwise, we use it verbatim for `RUSTC_LOG`.
-            // This way, if you set `MIRI_LOG=trace`, you get only the right parts of
-            // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_const_eval::interpret=debug`.
-            if tracing::Level::from_str(&var).is_ok() {
-                cfg.filter = Ok(format!(
-                    "rustc_middle::mir::interpret={var},rustc_const_eval::interpret={var},miri={var}"
-                ));
-            } else {
-                cfg.filter = Ok(var);
-            }
-        }
-    }
-
-    cfg
-}
-
-/// The global logger can only be set once per process, so track
-/// whether that already happened.
-static LOGGER_INITED: Once = Once::new();
-
-fn init_early_loggers(early_dcx: &EarlyDiagCtxt) {
-    // We only initialize `rustc` if the env var is set (so the user asked for it).
-    // If it is not set, we avoid initializing now so that we can initialize later with our custom
-    // settings, and *not* log anything for what happens before `miri` starts interpreting.
-    if env::var_os("RUSTC_LOG").is_some() {
-        LOGGER_INITED.call_once(|| {
-            rustc_driver::init_logger(early_dcx, rustc_logger_config());
-        });
-    }
+fn fatal_error_(msg: &impl std::fmt::Display) -> ! {
+    eprintln!("fatal error: {msg}");
+    exit(1)
 }
 
-fn init_late_loggers(early_dcx: &EarlyDiagCtxt, tcx: TyCtxt<'_>) {
-    // If the logger is not yet initialized, initialize it.
-    LOGGER_INITED.call_once(|| {
-        rustc_driver::init_logger(early_dcx, rustc_logger_config());
-    });
-
-    // If `MIRI_BACKTRACE` is set and `RUSTC_CTFE_BACKTRACE` is not, set `RUSTC_CTFE_BACKTRACE`.
-    // Do this late, so we ideally only apply this to Miri's errors.
-    if let Some(val) = env::var_os("MIRI_BACKTRACE") {
-        let ctfe_backtrace = match &*val.to_string_lossy() {
-            "immediate" => CtfeBacktrace::Immediate,
-            "0" => CtfeBacktrace::Disabled,
-            _ => CtfeBacktrace::Capture,
-        };
-        *tcx.sess.ctfe_backtrace.borrow_mut() = ctfe_backtrace;
-    }
+macro_rules! fatal_error {
+    ($($tt:tt)*) => { $crate::fatal_error_(&format_args!($($tt)*)) };
 }
+use fatal_error;
 
 /// Execute a compiler with the given CLI arguments and callbacks.
 fn run_compiler_and_exit(
     args: &[String],
     callbacks: &mut (dyn rustc_driver::Callbacks + Send),
 ) -> ! {
-    // Invoke compiler, and handle return code.
+    // Invoke compiler, catch any unwinding panics and handle return code.
     let exit_code =
         rustc_driver::catch_with_exit_code(move || rustc_driver::run_compiler(args, callbacks));
-    std::process::exit(exit_code)
+    exit(exit_code)
 }
 
 /// Parses a comma separated list of `T` from the given string:
@@ -566,7 +521,7 @@ fn main() {
                     params.precise_interior_mut = false;
                 }
                 _ =>
-                    show_error!(
+                    fatal_error!(
                         "`-Zmiri-tree-borrows` is required before `-Zmiri-tree-borrows-no-precise-interior-mut`"
                     ),
             };
@@ -593,7 +548,7 @@ fn main() {
                 "warn-nobacktrace" =>
                     miri::IsolatedOp::Reject(miri::RejectOpWith::WarningWithoutBacktrace),
                 _ =>
-                    show_error!(
+                    fatal_error!(
                         "-Zmiri-isolation-error must be `abort`, `hide`, `warn`, or `warn-nobacktrace`"
                     ),
             };
@@ -624,16 +579,16 @@ fn main() {
                 "all" => RetagFields::Yes,
                 "none" => RetagFields::No,
                 "scalar" => RetagFields::OnlyScalar,
-                _ => show_error!("`-Zmiri-retag-fields` can only be `all`, `none`, or `scalar`"),
+                _ => fatal_error!("`-Zmiri-retag-fields` can only be `all`, `none`, or `scalar`"),
             };
         } else if let Some(param) = arg.strip_prefix("-Zmiri-seed=") {
             let seed = param.parse::<u64>().unwrap_or_else(|_| {
-                show_error!("-Zmiri-seed must be an integer that fits into u64")
+                fatal_error!("-Zmiri-seed must be an integer that fits into u64")
             });
             miri_config.seed = Some(seed);
         } else if let Some(param) = arg.strip_prefix("-Zmiri-many-seeds=") {
             let range = parse_range(param).unwrap_or_else(|err| {
-                show_error!(
+                fatal_error!(
                     "-Zmiri-many-seeds requires a range in the form `from..to` or `..to`: {err}"
                 )
             });
@@ -650,51 +605,51 @@ fn main() {
             miri_config.forwarded_env_vars.push(param.to_owned());
         } else if let Some(param) = arg.strip_prefix("-Zmiri-env-set=") {
             let Some((name, value)) = param.split_once('=') else {
-                show_error!("-Zmiri-env-set requires an argument of the form <name>=<value>");
+                fatal_error!("-Zmiri-env-set requires an argument of the form <name>=<value>");
             };
             miri_config.set_env_vars.insert(name.to_owned(), value.to_owned());
         } else if let Some(param) = arg.strip_prefix("-Zmiri-track-pointer-tag=") {
             let ids: Vec<u64> = parse_comma_list(param).unwrap_or_else(|err| {
-                show_error!("-Zmiri-track-pointer-tag requires a comma separated list of valid `u64` arguments: {err}")
+                fatal_error!("-Zmiri-track-pointer-tag requires a comma separated list of valid `u64` arguments: {err}")
             });
             for id in ids.into_iter().map(miri::BorTag::new) {
                 if let Some(id) = id {
                     miri_config.tracked_pointer_tags.insert(id);
                 } else {
-                    show_error!("-Zmiri-track-pointer-tag requires nonzero arguments");
+                    fatal_error!("-Zmiri-track-pointer-tag requires nonzero arguments");
                 }
             }
         } else if let Some(param) = arg.strip_prefix("-Zmiri-track-alloc-id=") {
             let ids = parse_comma_list::<NonZero<u64>>(param).unwrap_or_else(|err| {
-                show_error!("-Zmiri-track-alloc-id requires a comma separated list of valid non-zero `u64` arguments: {err}")
+                fatal_error!("-Zmiri-track-alloc-id requires a comma separated list of valid non-zero `u64` arguments: {err}")
             });
             miri_config.tracked_alloc_ids.extend(ids.into_iter().map(miri::AllocId));
         } else if arg == "-Zmiri-track-alloc-accesses" {
             miri_config.track_alloc_accesses = true;
         } else if let Some(param) = arg.strip_prefix("-Zmiri-address-reuse-rate=") {
             miri_config.address_reuse_rate = parse_rate(param)
-                .unwrap_or_else(|err| show_error!("-Zmiri-address-reuse-rate {err}"));
+                .unwrap_or_else(|err| fatal_error!("-Zmiri-address-reuse-rate {err}"));
         } else if let Some(param) = arg.strip_prefix("-Zmiri-address-reuse-cross-thread-rate=") {
             miri_config.address_reuse_cross_thread_rate = parse_rate(param)
-                .unwrap_or_else(|err| show_error!("-Zmiri-address-reuse-cross-thread-rate {err}"));
+                .unwrap_or_else(|err| fatal_error!("-Zmiri-address-reuse-cross-thread-rate {err}"));
         } else if let Some(param) = arg.strip_prefix("-Zmiri-compare-exchange-weak-failure-rate=") {
             miri_config.cmpxchg_weak_failure_rate = parse_rate(param).unwrap_or_else(|err| {
-                show_error!("-Zmiri-compare-exchange-weak-failure-rate {err}")
+                fatal_error!("-Zmiri-compare-exchange-weak-failure-rate {err}")
             });
         } else if let Some(param) = arg.strip_prefix("-Zmiri-preemption-rate=") {
-            miri_config.preemption_rate =
-                parse_rate(param).unwrap_or_else(|err| show_error!("-Zmiri-preemption-rate {err}"));
+            miri_config.preemption_rate = parse_rate(param)
+                .unwrap_or_else(|err| fatal_error!("-Zmiri-preemption-rate {err}"));
         } else if arg == "-Zmiri-report-progress" {
             // This makes it take a few seconds between progress reports on my laptop.
             miri_config.report_progress = Some(1_000_000);
         } else if let Some(param) = arg.strip_prefix("-Zmiri-report-progress=") {
             let interval = param.parse::<u32>().unwrap_or_else(|err| {
-                show_error!("-Zmiri-report-progress requires a `u32`: {}", err)
+                fatal_error!("-Zmiri-report-progress requires a `u32`: {}", err)
             });
             miri_config.report_progress = Some(interval);
         } else if let Some(param) = arg.strip_prefix("-Zmiri-provenance-gc=") {
             let interval = param.parse::<u32>().unwrap_or_else(|err| {
-                show_error!("-Zmiri-provenance-gc requires a `u32`: {}", err)
+                fatal_error!("-Zmiri-provenance-gc requires a `u32`: {}", err)
             });
             miri_config.gc_interval = interval;
         } else if let Some(param) = arg.strip_prefix("-Zmiri-measureme=") {
@@ -704,7 +659,7 @@ fn main() {
                 "0" => BacktraceStyle::Off,
                 "1" => BacktraceStyle::Short,
                 "full" => BacktraceStyle::Full,
-                _ => show_error!("-Zmiri-backtrace may only be 0, 1, or full"),
+                _ => fatal_error!("-Zmiri-backtrace may only be 0, 1, or full"),
             };
         } else if let Some(param) = arg.strip_prefix("-Zmiri-native-lib=") {
             let filename = param.to_string();
@@ -721,25 +676,27 @@ fn main() {
                     miri_config.native_lib.push(filename.into());
                 }
             } else {
-                show_error!("-Zmiri-native-lib `{}` does not exist", filename);
+                fatal_error!("-Zmiri-native-lib `{}` does not exist", filename);
             }
+        } else if arg == "-Zmiri-native-lib-enable-tracing" {
+            miri_config.native_lib_enable_tracing = true;
         } else if let Some(param) = arg.strip_prefix("-Zmiri-num-cpus=") {
             let num_cpus = param
                 .parse::<u32>()
-                .unwrap_or_else(|err| show_error!("-Zmiri-num-cpus requires a `u32`: {}", err));
+                .unwrap_or_else(|err| fatal_error!("-Zmiri-num-cpus requires a `u32`: {}", err));
             if !(1..=miri::MAX_CPUS).contains(&usize::try_from(num_cpus).unwrap()) {
-                show_error!("-Zmiri-num-cpus must be in the range 1..={}", miri::MAX_CPUS);
+                fatal_error!("-Zmiri-num-cpus must be in the range 1..={}", miri::MAX_CPUS);
             }
             miri_config.num_cpus = num_cpus;
         } else if let Some(param) = arg.strip_prefix("-Zmiri-force-page-size=") {
             let page_size = param.parse::<u64>().unwrap_or_else(|err| {
-                show_error!("-Zmiri-force-page-size requires a `u64`: {}", err)
+                fatal_error!("-Zmiri-force-page-size requires a `u64`: {}", err)
             });
             // Convert from kilobytes to bytes.
             let page_size = if page_size.is_power_of_two() {
                 page_size * 1024
             } else {
-                show_error!("-Zmiri-force-page-size requires a power of 2: {page_size}");
+                fatal_error!("-Zmiri-force-page-size requires a power of 2: {page_size}");
             };
             miri_config.page_size = Some(page_size);
         } else {
@@ -750,22 +707,22 @@ fn main() {
     // Tree Borrows implies strict provenance, and is not compatible with native calls.
     if matches!(miri_config.borrow_tracker, Some(BorrowTrackerMethod::TreeBorrows { .. })) {
         if miri_config.provenance_mode != ProvenanceMode::Strict {
-            show_error!(
+            fatal_error!(
                 "Tree Borrows does not support integer-to-pointer casts, and hence requires strict provenance"
             );
         }
         if !miri_config.native_lib.is_empty() {
-            show_error!("Tree Borrows is not compatible with calling native functions");
+            fatal_error!("Tree Borrows is not compatible with calling native functions");
         }
     }
 
     // Native calls and strict provenance are not compatible.
     if !miri_config.native_lib.is_empty() && miri_config.provenance_mode == ProvenanceMode::Strict {
-        show_error!("strict provenance is not compatible with calling native functions");
+        fatal_error!("strict provenance is not compatible with calling native functions");
     }
     // You can set either one seed or many.
     if many_seeds.is_some() && miri_config.seed.is_some() {
-        show_error!("Only one of `-Zmiri-seed` and `-Zmiri-many-seeds can be set");
+        fatal_error!("Only one of `-Zmiri-seed` and `-Zmiri-many-seeds can be set");
     }
 
     // Ensure we have parallelism for many-seeds mode.
@@ -781,18 +738,28 @@ fn main() {
     assert_eq!(genmc_config.is_some(), miri_config.genmc_mode);
     if genmc_config.is_some() {
         if !miri_config.data_race_detector {
-            show_error!("Cannot disable data race detection in GenMC mode (currently)");
+            fatal_error!("Cannot disable data race detection in GenMC mode (currently)");
         } else if !miri_config.weak_memory_emulation {
-            show_error!("Cannot disable weak memory emulation in GenMC mode");
+            fatal_error!("Cannot disable weak memory emulation in GenMC mode");
         }
     } else if miri_config.weak_memory_emulation && !miri_config.data_race_detector {
-        show_error!(
+        fatal_error!(
             "Weak memory emulation cannot be enabled when the data race detector is disabled"
         );
     };
 
     debug!("rustc arguments: {:?}", rustc_args);
     debug!("crate arguments: {:?}", miri_config.args);
+    #[cfg(target_os = "linux")]
+    if !miri_config.native_lib.is_empty() && miri_config.native_lib_enable_tracing {
+        // FIXME: This should display a diagnostic / warning on error
+        // SAFETY: If any other threads exist at this point (namely for the ctrlc
+        // handler), they will not interact with anything on the main rustc/Miri
+        // thread in an async-signal-unsafe way such as by accessing shared
+        // semaphores, etc.; the handler only calls `sleep()` and `exit()`, which
+        // are async-signal-safe, as is accessing atomics
+        //let _ = unsafe { miri::native_lib::init_sv() };
+    }
     run_compiler_and_exit(
         &rustc_args,
         &mut MiriCompilerCalls::new(miri_config, many_seeds, genmc_config),
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
index 99171b0349e..a0761cb07a1 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -468,10 +468,8 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // - when `extern type` is involved we use the size of the known prefix,
         // - if the pointer is not reborrowed (raw pointer) then we override the size
         //   to do a zero-length reborrow.
-        let reborrow_size = this
-            .size_and_align_of_val(place)?
-            .map(|(size, _)| size)
-            .unwrap_or(place.layout.size);
+        let reborrow_size =
+            this.size_and_align_of_val(place)?.map(|(size, _)| size).unwrap_or(place.layout.size);
         trace!("Creating new permission: {:?} with size {:?}", new_perm, reborrow_size);
 
         // This new tag is not guaranteed to actually be used.
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs
index dcd5a6cb023..ad0a565dfd8 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs
@@ -327,7 +327,7 @@ mod tests {
         for i in 0..1000 {
             i.hash(&mut hasher);
             let rng = hasher.finish();
-            let op = rng % 3 == 0;
+            let op = rng.is_multiple_of(3);
             let key = (rng / 2) % 50;
             let val = (rng / 100) % 1000;
             if op {
diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs
index 714eb1fba91..b5e7e9d0ac0 100644
--- a/src/tools/miri/src/concurrency/data_race.rs
+++ b/src/tools/miri/src/concurrency/data_race.rs
@@ -971,14 +971,6 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
         }
     }
 
-    /// After all threads are done running, this allows data races to occur for subsequent
-    /// 'administrative' machine accesses (that logically happen outside of the Abstract Machine).
-    fn allow_data_races_all_threads_done(&mut self) {
-        let this = self.eval_context_ref();
-        assert!(this.have_all_terminated());
-        this.machine.data_race.set_ongoing_action_data_race_free(true);
-    }
-
     /// Calls the callback with the "release" clock of the current thread.
     /// Other threads can acquire this clock in the future to establish synchronization
     /// with this program point.
diff --git a/src/tools/miri/src/concurrency/init_once.rs b/src/tools/miri/src/concurrency/init_once.rs
index c26384f65f6..165215f9270 100644
--- a/src/tools/miri/src/concurrency/init_once.rs
+++ b/src/tools/miri/src/concurrency/init_once.rs
@@ -1,13 +1,11 @@
+use std::cell::RefCell;
 use std::collections::VecDeque;
-
-use rustc_index::Idx;
+use std::rc::Rc;
 
 use super::thread::DynUnblockCallback;
 use super::vector_clock::VClock;
 use crate::*;
 
-super::sync::declare_id!(InitOnceId);
-
 #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
 /// The current status of a one time initialization.
 pub enum InitOnceStatus {
@@ -25,44 +23,70 @@ pub(super) struct InitOnce {
     clock: VClock,
 }
 
-impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
-pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
+impl InitOnce {
     #[inline]
-    fn init_once_status(&mut self, id: InitOnceId) -> InitOnceStatus {
-        let this = self.eval_context_ref();
-        this.machine.sync.init_onces[id].status
-    }
-
-    /// Put the thread into the queue waiting for the initialization.
-    #[inline]
-    fn init_once_enqueue_and_block(&mut self, id: InitOnceId, callback: DynUnblockCallback<'tcx>) {
-        let this = self.eval_context_mut();
-        let thread = this.active_thread();
-        let init_once = &mut this.machine.sync.init_onces[id];
-        assert_ne!(init_once.status, InitOnceStatus::Complete, "queueing on complete init once");
-        init_once.waiters.push_back(thread);
-        this.block_thread(BlockReason::InitOnce(id), None, callback);
+    pub fn status(&self) -> InitOnceStatus {
+        self.status
     }
 
     /// Begin initializing this InitOnce. Must only be called after checking that it is currently
     /// uninitialized.
     #[inline]
-    fn init_once_begin(&mut self, id: InitOnceId) {
-        let this = self.eval_context_mut();
-        let init_once = &mut this.machine.sync.init_onces[id];
+    pub fn begin(&mut self) {
         assert_eq!(
-            init_once.status,
+            self.status(),
             InitOnceStatus::Uninitialized,
             "beginning already begun or complete init once"
         );
-        init_once.status = InitOnceStatus::Begun;
+        self.status = InitOnceStatus::Begun;
     }
+}
 
+#[derive(Default, Clone, Debug)]
+pub struct InitOnceRef(Rc<RefCell<InitOnce>>);
+
+impl InitOnceRef {
+    pub fn new() -> Self {
+        Self(Default::default())
+    }
+
+    pub fn status(&self) -> InitOnceStatus {
+        self.0.borrow().status()
+    }
+
+    pub fn begin(&self) {
+        self.0.borrow_mut().begin();
+    }
+}
+
+impl VisitProvenance for InitOnceRef {
+    // InitOnce contains no provenance.
+    fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {}
+}
+
+impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
+pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
+    /// Put the thread into the queue waiting for the initialization.
     #[inline]
-    fn init_once_complete(&mut self, id: InitOnceId) -> InterpResult<'tcx> {
+    fn init_once_enqueue_and_block(
+        &mut self,
+        init_once_ref: InitOnceRef,
+        callback: DynUnblockCallback<'tcx>,
+    ) {
         let this = self.eval_context_mut();
-        let init_once = &mut this.machine.sync.init_onces[id];
+        let thread = this.active_thread();
+        let mut init_once = init_once_ref.0.borrow_mut();
+        assert_ne!(init_once.status, InitOnceStatus::Complete, "queueing on complete init once");
+
+        init_once.waiters.push_back(thread);
+        this.block_thread(BlockReason::InitOnce, None, callback);
+    }
 
+    #[inline]
+    fn init_once_complete(&mut self, init_once_ref: &InitOnceRef) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+
+        let mut init_once = init_once_ref.0.borrow_mut();
         assert_eq!(
             init_once.status,
             InitOnceStatus::Begun,
@@ -79,17 +103,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         // Wake up everyone.
         // need to take the queue to avoid having `this` be borrowed multiple times
-        for waiter in std::mem::take(&mut init_once.waiters) {
-            this.unblock_thread(waiter, BlockReason::InitOnce(id))?;
+        let waiters = std::mem::take(&mut init_once.waiters);
+        drop(init_once);
+        for waiter in waiters {
+            this.unblock_thread(waiter, BlockReason::InitOnce)?;
         }
 
         interp_ok(())
     }
 
     #[inline]
-    fn init_once_fail(&mut self, id: InitOnceId) -> InterpResult<'tcx> {
+    fn init_once_fail(&mut self, init_once_ref: &InitOnceRef) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        let init_once = &mut this.machine.sync.init_onces[id];
+        let mut init_once = init_once_ref.0.borrow_mut();
         assert_eq!(
             init_once.status,
             InitOnceStatus::Begun,
@@ -106,7 +132,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         // Wake up one waiting thread, so they can go ahead and try to init this.
         if let Some(waiter) = init_once.waiters.pop_front() {
-            this.unblock_thread(waiter, BlockReason::InitOnce(id))?;
+            drop(init_once);
+            this.unblock_thread(waiter, BlockReason::InitOnce)?;
         }
 
         interp_ok(())
@@ -115,15 +142,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     /// Synchronize with the previous completion of an InitOnce.
     /// Must only be called after checking that it is complete.
     #[inline]
-    fn init_once_observe_completed(&mut self, id: InitOnceId) {
+    fn init_once_observe_completed(&mut self, init_once_ref: &InitOnceRef) {
         let this = self.eval_context_mut();
+        let init_once = init_once_ref.0.borrow();
 
         assert_eq!(
-            this.init_once_status(id),
+            init_once.status,
             InitOnceStatus::Complete,
             "observing the completion of incomplete init once"
         );
 
-        this.acquire_clock(&this.machine.sync.init_onces[id].clock);
+        this.acquire_clock(&init_once.clock);
     }
 }
diff --git a/src/tools/miri/src/concurrency/mod.rs b/src/tools/miri/src/concurrency/mod.rs
index aaa3fc85a6c..49bcc0d30b5 100644
--- a/src/tools/miri/src/concurrency/mod.rs
+++ b/src/tools/miri/src/concurrency/mod.rs
@@ -8,30 +8,10 @@ pub mod thread;
 mod vector_clock;
 pub mod weak_memory;
 
-// cfg(bootstrap)
-macro_rules! cfg_select_dispatch {
-    ($($tokens:tt)*) => {
-        #[cfg(bootstrap)]
-        cfg_match! { $($tokens)* }
-
-        #[cfg(not(bootstrap))]
-        cfg_select! { $($tokens)* }
-    };
-}
-
 // Import either the real genmc adapter or a dummy module.
-cfg_select_dispatch! {
-    feature = "genmc" => {
-        mod genmc;
-        pub use self::genmc::{GenmcCtx, GenmcConfig};
-    }
-    _ => {
-        #[path = "genmc/dummy.rs"]
-        mod genmc_dummy;
-        use self::genmc_dummy as genmc;
-        pub use self::genmc::{GenmcCtx, GenmcConfig};
-    }
-}
+#[cfg_attr(not(feature = "genmc"), path = "genmc/dummy.rs")]
+mod genmc;
 
 pub use self::data_race_handler::{AllocDataRaceHandler, GlobalDataRaceHandler};
+pub use self::genmc::{GenmcConfig, GenmcCtx};
 pub use self::vector_clock::VClock;
diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs
index 74379d6438d..179094db0fe 100644
--- a/src/tools/miri/src/concurrency/sync.rs
+++ b/src/tools/miri/src/concurrency/sync.rs
@@ -8,45 +8,10 @@ use std::time::Duration;
 
 use rustc_abi::Size;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_index::{Idx, IndexVec};
 
-use super::init_once::InitOnce;
 use super::vector_clock::VClock;
 use crate::*;
 
-/// We cannot use the `newtype_index!` macro because we have to use 0 as a
-/// sentinel value meaning that the identifier is not assigned. This is because
-/// the pthreads static initializers initialize memory with zeros (see the
-/// `src/shims/sync.rs` file).
-macro_rules! declare_id {
-    ($name: ident) => {
-        /// 0 is used to indicate that the id was not yet assigned and,
-        /// therefore, is not a valid identifier.
-        #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
-        pub struct $name(std::num::NonZero<u32>);
-
-        impl $crate::VisitProvenance for $name {
-            fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {}
-        }
-
-        impl Idx for $name {
-            fn new(idx: usize) -> Self {
-                // We use 0 as a sentinel value (see the comment above) and,
-                // therefore, need to shift by one when converting from an index
-                // into a vector.
-                let shifted_idx = u32::try_from(idx).unwrap().strict_add(1);
-                $name(std::num::NonZero::new(shifted_idx).unwrap())
-            }
-            fn index(self) -> usize {
-                // See the comment in `Self::new`.
-                // (This cannot underflow because `self.0` is `NonZero<u32>`.)
-                usize::try_from(self.0.get() - 1).unwrap()
-            }
-        }
-    };
-}
-pub(super) use declare_id;
-
 /// The mutex state.
 #[derive(Default, Debug)]
 struct Mutex {
@@ -64,8 +29,8 @@ struct Mutex {
 pub struct MutexRef(Rc<RefCell<Mutex>>);
 
 impl MutexRef {
-    fn new() -> Self {
-        MutexRef(Rc::new(RefCell::new(Mutex::default())))
+    pub fn new() -> Self {
+        Self(Default::default())
     }
 
     /// Get the id of the thread that currently owns this lock, or `None` if it is not locked.
@@ -75,9 +40,8 @@ impl MutexRef {
 }
 
 impl VisitProvenance for MutexRef {
-    fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
-        // Mutex contains no provenance.
-    }
+    // Mutex contains no provenance.
+    fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {}
 }
 
 /// The read-write lock state.
@@ -138,8 +102,8 @@ impl RwLock {
 pub struct RwLockRef(Rc<RefCell<RwLock>>);
 
 impl RwLockRef {
-    fn new() -> Self {
-        RwLockRef(Rc::new(RefCell::new(RwLock::default())))
+    pub fn new() -> Self {
+        Self(Default::default())
     }
 
     pub fn is_locked(&self) -> bool {
@@ -152,13 +116,10 @@ impl RwLockRef {
 }
 
 impl VisitProvenance for RwLockRef {
-    fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
-        // RwLockRef contains no provenance.
-    }
+    // RwLock contains no provenance.
+    fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {}
 }
 
-declare_id!(CondvarId);
-
 /// The conditional variable state.
 #[derive(Default, Debug)]
 struct Condvar {
@@ -171,6 +132,24 @@ struct Condvar {
     clock: VClock,
 }
 
+#[derive(Default, Clone, Debug)]
+pub struct CondvarRef(Rc<RefCell<Condvar>>);
+
+impl CondvarRef {
+    pub fn new() -> Self {
+        Self(Default::default())
+    }
+
+    pub fn is_awaited(&self) -> bool {
+        !self.0.borrow().waiters.is_empty()
+    }
+}
+
+impl VisitProvenance for CondvarRef {
+    // Condvar contains no provenance.
+    fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {}
+}
+
 /// The futex state.
 #[derive(Default, Debug)]
 struct Futex {
@@ -183,19 +162,22 @@ struct Futex {
     clock: VClock,
 }
 
-#[derive(Default, Clone)]
+#[derive(Default, Clone, Debug)]
 pub struct FutexRef(Rc<RefCell<Futex>>);
 
 impl FutexRef {
+    pub fn new() -> Self {
+        Self(Default::default())
+    }
+
     pub fn waiters(&self) -> usize {
         self.0.borrow().waiters.len()
     }
 }
 
 impl VisitProvenance for FutexRef {
-    fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
-        // No provenance in `Futex`.
-    }
+    // Futex contains no provenance.
+    fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {}
 }
 
 /// A thread waiting on a futex.
@@ -207,13 +189,6 @@ struct FutexWaiter {
     bitset: u32,
 }
 
-/// The state of all synchronization objects.
-#[derive(Default, Debug)]
-pub struct SynchronizationObjects {
-    condvars: IndexVec<CondvarId, Condvar>,
-    pub(super) init_onces: IndexVec<InitOnceId, InitOnce>,
-}
-
 // Private extension trait for local helper methods
 impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
 pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
@@ -237,23 +212,6 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
     }
 }
 
-impl SynchronizationObjects {
-    pub fn mutex_create(&mut self) -> MutexRef {
-        MutexRef::new()
-    }
-    pub fn rwlock_create(&mut self) -> RwLockRef {
-        RwLockRef::new()
-    }
-
-    pub fn condvar_create(&mut self) -> CondvarId {
-        self.condvars.push(Default::default())
-    }
-
-    pub fn init_once_create(&mut self) -> InitOnceId {
-        self.init_onces.push(Default::default())
-    }
-}
-
 impl<'tcx> AllocExtra<'tcx> {
     fn get_sync<T: 'static>(&self, offset: Size) -> Option<&T> {
         self.sync.get(&offset).and_then(|s| s.downcast_ref::<T>())
@@ -663,19 +621,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         );
     }
 
-    /// Is the conditional variable awaited?
-    #[inline]
-    fn condvar_is_awaited(&mut self, id: CondvarId) -> bool {
-        let this = self.eval_context_mut();
-        !this.machine.sync.condvars[id].waiters.is_empty()
-    }
-
     /// Release the mutex and let the current thread wait on the given condition variable.
     /// Once it is signaled, the mutex will be acquired and `retval_succ` will be written to `dest`.
     /// If the timeout happens first, `retval_timeout` will be written to `dest`.
     fn condvar_wait(
         &mut self,
-        condvar: CondvarId,
+        condvar_ref: CondvarRef,
         mutex_ref: MutexRef,
         timeout: Option<(TimeoutClock, TimeoutAnchor, Duration)>,
         retval_succ: Scalar,
@@ -695,14 +646,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             );
         }
         let thread = this.active_thread();
-        let waiters = &mut this.machine.sync.condvars[condvar].waiters;
-        waiters.push_back(thread);
+
+        condvar_ref.0.borrow_mut().waiters.push_back(thread);
         this.block_thread(
-            BlockReason::Condvar(condvar),
+            BlockReason::Condvar,
             timeout,
             callback!(
                 @capture<'tcx> {
-                    condvar: CondvarId,
+                    condvar_ref: CondvarRef,
                     mutex_ref: MutexRef,
                     retval_succ: Scalar,
                     retval_timeout: Scalar,
@@ -714,7 +665,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                             // The condvar was signaled. Make sure we get the clock for that.
                             if let Some(data_race) = this.machine.data_race.as_vclocks_ref() {
                                 data_race.acquire_clock(
-                                    &this.machine.sync.condvars[condvar].clock,
+                                    &condvar_ref.0.borrow().clock,
                                     &this.machine.threads,
                                 );
                             }
@@ -725,7 +676,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         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;
+                            let waiters = &mut condvar_ref.0.borrow_mut().waiters;
                             waiters.retain(|waiter| *waiter != thread);
                             // Now get back the lock.
                             this.condvar_reacquire_mutex(mutex_ref, retval_timeout, dest)
@@ -739,9 +690,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
     /// Wake up some thread (if there is any) sleeping on the conditional
     /// variable. Returns `true` iff any thread was woken up.
-    fn condvar_signal(&mut self, id: CondvarId) -> InterpResult<'tcx, bool> {
+    fn condvar_signal(&mut self, condvar_ref: &CondvarRef) -> InterpResult<'tcx, bool> {
         let this = self.eval_context_mut();
-        let condvar = &mut this.machine.sync.condvars[id];
+        let mut condvar = condvar_ref.0.borrow_mut();
 
         // Each condvar signal happens-before the end of the condvar wake
         if let Some(data_race) = this.machine.data_race.as_vclocks_ref() {
@@ -750,7 +701,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let Some(waiter) = condvar.waiters.pop_front() else {
             return interp_ok(false);
         };
-        this.unblock_thread(waiter, BlockReason::Condvar(id))?;
+        drop(condvar);
+        this.unblock_thread(waiter, BlockReason::Condvar)?;
         interp_ok(true)
     }
 
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index 38b5d4c0f06..a4e93f9222c 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -97,13 +97,13 @@ pub enum BlockReason {
     /// Blocked on a mutex.
     Mutex,
     /// Blocked on a condition variable.
-    Condvar(CondvarId),
+    Condvar,
     /// Blocked on a reader-writer lock.
     RwLock,
     /// Blocked on a Futex variable.
     Futex,
     /// Blocked on an InitOnce.
-    InitOnce(InitOnceId),
+    InitOnce,
     /// Blocked on epoll.
     Epoll,
     /// Blocked on eventfd.
@@ -582,88 +582,6 @@ impl<'tcx> ThreadManager<'tcx> {
         interp_ok(())
     }
 
-    /// Mark that the active thread tries to join the thread with `joined_thread_id`.
-    fn join_thread(
-        &mut self,
-        joined_thread_id: ThreadId,
-        data_race_handler: &mut GlobalDataRaceHandler,
-    ) -> InterpResult<'tcx> {
-        if self.threads[joined_thread_id].join_status == ThreadJoinStatus::Detached {
-            // On Windows this corresponds to joining on a closed handle.
-            throw_ub_format!("trying to join a detached thread");
-        }
-
-        fn after_join<'tcx>(
-            threads: &mut ThreadManager<'_>,
-            joined_thread_id: ThreadId,
-            data_race_handler: &mut GlobalDataRaceHandler,
-        ) -> InterpResult<'tcx> {
-            match data_race_handler {
-                GlobalDataRaceHandler::None => {}
-                GlobalDataRaceHandler::Vclocks(data_race) =>
-                    data_race.thread_joined(threads, joined_thread_id),
-                GlobalDataRaceHandler::Genmc(genmc_ctx) =>
-                    genmc_ctx.handle_thread_join(threads.active_thread, joined_thread_id)?,
-            }
-            interp_ok(())
-        }
-
-        // Mark the joined thread as being joined so that we detect if other
-        // threads try to join it.
-        self.threads[joined_thread_id].join_status = ThreadJoinStatus::Joined;
-        if !self.threads[joined_thread_id].state.is_terminated() {
-            trace!(
-                "{:?} blocked on {:?} when trying to join",
-                self.active_thread, joined_thread_id
-            );
-            // The joined thread is still running, we need to wait for it.
-            // Unce we get unblocked, perform the appropriate synchronization.
-            self.block_thread(
-                BlockReason::Join(joined_thread_id),
-                None,
-                callback!(
-                    @capture<'tcx> {
-                        joined_thread_id: ThreadId,
-                    }
-                    |this, unblock: UnblockKind| {
-                        assert_eq!(unblock, UnblockKind::Ready);
-                        after_join(&mut this.machine.threads, joined_thread_id, &mut this.machine.data_race)
-                    }
-                ),
-            );
-        } else {
-            // The thread has already terminated - establish happens-before
-            after_join(self, joined_thread_id, data_race_handler)?;
-        }
-        interp_ok(())
-    }
-
-    /// Mark that the active thread tries to exclusively join the thread with `joined_thread_id`.
-    /// If the thread is already joined by another thread, it will throw UB
-    fn join_thread_exclusive(
-        &mut self,
-        joined_thread_id: ThreadId,
-        data_race_handler: &mut GlobalDataRaceHandler,
-    ) -> InterpResult<'tcx> {
-        if self.threads[joined_thread_id].join_status == ThreadJoinStatus::Joined {
-            throw_ub_format!("trying to join an already joined thread");
-        }
-
-        if joined_thread_id == self.active_thread {
-            throw_ub_format!("trying to join itself");
-        }
-
-        // Sanity check `join_status`.
-        assert!(
-            self.threads
-                .iter()
-                .all(|thread| { !thread.state.is_blocked_on(BlockReason::Join(joined_thread_id)) }),
-            "this thread already has threads waiting for its termination"
-        );
-
-        self.join_thread(joined_thread_id, data_race_handler)
-    }
-
     /// Set the name of the given thread.
     pub fn set_thread_name(&mut self, thread: ThreadId, new_thread_name: Vec<u8>) {
         self.threads[thread].thread_name = Some(new_thread_name);
@@ -976,7 +894,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             start_abi,
             &[func_arg],
             Some(&ret_place),
-            StackPopCleanup::Root { cleanup: true },
+            ReturnContinuation::Stop { cleanup: true },
         )?;
 
         // Restore the old active thread frame.
@@ -1114,20 +1032,102 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         this.machine.threads.detach_thread(thread_id, allow_terminated_joined)
     }
 
-    #[inline]
-    fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> {
+    /// Mark that the active thread tries to join the thread with `joined_thread_id`.
+    ///
+    /// When the join is successful (immediately, or as soon as the joined thread finishes), `success_retval` will be written to `return_dest`.
+    fn join_thread(
+        &mut self,
+        joined_thread_id: ThreadId,
+        success_retval: Scalar,
+        return_dest: &MPlaceTy<'tcx>,
+    ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        this.machine.threads.join_thread(joined_thread_id, &mut this.machine.data_race)?;
+        let thread_mgr = &mut this.machine.threads;
+        if thread_mgr.threads[joined_thread_id].join_status == ThreadJoinStatus::Detached {
+            // On Windows this corresponds to joining on a closed handle.
+            throw_ub_format!("trying to join a detached thread");
+        }
+
+        fn after_join<'tcx>(
+            this: &mut InterpCx<'tcx, MiriMachine<'tcx>>,
+            joined_thread_id: ThreadId,
+            success_retval: Scalar,
+            return_dest: &MPlaceTy<'tcx>,
+        ) -> InterpResult<'tcx> {
+            let threads = &this.machine.threads;
+            match &mut this.machine.data_race {
+                GlobalDataRaceHandler::None => {}
+                GlobalDataRaceHandler::Vclocks(data_race) =>
+                    data_race.thread_joined(threads, joined_thread_id),
+                GlobalDataRaceHandler::Genmc(genmc_ctx) =>
+                    genmc_ctx.handle_thread_join(threads.active_thread, joined_thread_id)?,
+            }
+            this.write_scalar(success_retval, return_dest)?;
+            interp_ok(())
+        }
+
+        // Mark the joined thread as being joined so that we detect if other
+        // threads try to join it.
+        thread_mgr.threads[joined_thread_id].join_status = ThreadJoinStatus::Joined;
+        if !thread_mgr.threads[joined_thread_id].state.is_terminated() {
+            trace!(
+                "{:?} blocked on {:?} when trying to join",
+                thread_mgr.active_thread, joined_thread_id
+            );
+            // The joined thread is still running, we need to wait for it.
+            // Once we get unblocked, perform the appropriate synchronization and write the return value.
+            let dest = return_dest.clone();
+            thread_mgr.block_thread(
+                BlockReason::Join(joined_thread_id),
+                None,
+                callback!(
+                    @capture<'tcx> {
+                        joined_thread_id: ThreadId,
+                        dest: MPlaceTy<'tcx>,
+                        success_retval: Scalar,
+                    }
+                    |this, unblock: UnblockKind| {
+                        assert_eq!(unblock, UnblockKind::Ready);
+                        after_join(this, joined_thread_id, success_retval, &dest)
+                    }
+                ),
+            );
+        } else {
+            // The thread has already terminated - establish happens-before and write the return value.
+            after_join(this, joined_thread_id, success_retval, return_dest)?;
+        }
         interp_ok(())
     }
 
-    #[inline]
-    fn join_thread_exclusive(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> {
+    /// Mark that the active thread tries to exclusively join the thread with `joined_thread_id`.
+    /// If the thread is already joined by another thread, it will throw UB.
+    ///
+    /// When the join is successful (immediately, or as soon as the joined thread finishes), `success_retval` will be written to `return_dest`.
+    fn join_thread_exclusive(
+        &mut self,
+        joined_thread_id: ThreadId,
+        success_retval: Scalar,
+        return_dest: &MPlaceTy<'tcx>,
+    ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        this.machine
-            .threads
-            .join_thread_exclusive(joined_thread_id, &mut this.machine.data_race)?;
-        interp_ok(())
+        let threads = &this.machine.threads.threads;
+        if threads[joined_thread_id].join_status == ThreadJoinStatus::Joined {
+            throw_ub_format!("trying to join an already joined thread");
+        }
+
+        if joined_thread_id == this.machine.threads.active_thread {
+            throw_ub_format!("trying to join itself");
+        }
+
+        // Sanity check `join_status`.
+        assert!(
+            threads
+                .iter()
+                .all(|thread| { !thread.state.is_blocked_on(BlockReason::Join(joined_thread_id)) }),
+            "this thread already has threads waiting for its termination"
+        );
+
+        this.join_thread(joined_thread_id, success_retval, return_dest)
     }
 
     #[inline]
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 54a7c1407ea..9ecbd31c5b9 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -132,7 +132,9 @@ pub enum NonHaltingDiagnostic {
     Int2Ptr {
         details: bool,
     },
-    NativeCallSharedMem,
+    NativeCallSharedMem {
+        tracing: bool,
+    },
     WeakMemoryOutdatedLoad {
         ptr: Pointer,
     },
@@ -627,7 +629,7 @@ impl<'tcx> MiriMachine<'tcx> {
             RejectedIsolatedOp(_) =>
                 ("operation rejected by isolation".to_string(), DiagLevel::Warning),
             Int2Ptr { .. } => ("integer-to-pointer cast".to_string(), DiagLevel::Warning),
-            NativeCallSharedMem =>
+            NativeCallSharedMem { .. } =>
                 ("sharing memory with a native function".to_string(), DiagLevel::Warning),
             ExternTypeReborrow =>
                 ("reborrow of reference to `extern type`".to_string(), DiagLevel::Warning),
@@ -663,7 +665,8 @@ impl<'tcx> MiriMachine<'tcx> {
             ProgressReport { .. } =>
                 format!("progress report: current operation being executed is here"),
             Int2Ptr { .. } => format!("integer-to-pointer cast"),
-            NativeCallSharedMem => format!("sharing memory with a native function called via FFI"),
+            NativeCallSharedMem { .. } =>
+                format!("sharing memory with a native function called via FFI"),
             WeakMemoryOutdatedLoad { ptr } =>
                 format!("weak memory emulation: outdated value returned from load at {ptr}"),
             ExternTypeReborrow =>
@@ -709,22 +712,41 @@ impl<'tcx> MiriMachine<'tcx> {
                 }
                 v
             }
-            NativeCallSharedMem => {
-                vec![
-                    note!(
-                        "when memory is shared with a native function call, Miri stops tracking initialization and provenance for that memory"
-                    ),
-                    note!(
-                        "in particular, Miri assumes that the native call initializes all memory it has access to"
-                    ),
-                    note!(
-                        "Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory"
-                    ),
-                    note!(
-                        "what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free"
-                    ),
-                ]
-            }
+            NativeCallSharedMem { tracing } =>
+                if *tracing {
+                    vec![
+                        note!(
+                            "when memory is shared with a native function call, Miri can only track initialisation and provenance on a best-effort basis"
+                        ),
+                        note!(
+                            "in particular, Miri assumes that the native call initializes all memory it has written to"
+                        ),
+                        note!(
+                            "Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory"
+                        ),
+                        note!(
+                            "what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free"
+                        ),
+                        note!(
+                            "tracing memory accesses in native code is not yet fully implemented, so there can be further imprecisions beyond what is documented here"
+                        ),
+                    ]
+                } else {
+                    vec![
+                        note!(
+                            "when memory is shared with a native function call, Miri stops tracking initialization and provenance for that memory"
+                        ),
+                        note!(
+                            "in particular, Miri assumes that the native call initializes all memory it has access to"
+                        ),
+                        note!(
+                            "Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory"
+                        ),
+                        note!(
+                            "what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free"
+                        ),
+                    ]
+                },
             ExternTypeReborrow => {
                 assert!(self.borrow_tracker.as_ref().is_some_and(|b| {
                     matches!(
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 04fe08b30ee..425a136dfa5 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -150,6 +150,8 @@ pub struct MiriConfig {
     pub retag_fields: RetagFields,
     /// The location of the shared object files to load when calling external functions
     pub native_lib: Vec<PathBuf>,
+    /// Whether to enable the new native lib tracing system.
+    pub native_lib_enable_tracing: bool,
     /// Run a garbage collector for BorTags every N basic blocks.
     pub gc_interval: u32,
     /// The number of CPUs to be reported by miri.
@@ -199,6 +201,7 @@ impl Default for MiriConfig {
             report_progress: None,
             retag_fields: RetagFields::Yes,
             native_lib: vec![],
+            native_lib_enable_tracing: false,
             gc_interval: 10_000,
             num_cpus: 1,
             page_size: None,
@@ -280,16 +283,6 @@ impl<'tcx> MainThreadState<'tcx> {
                 // to be like a global `static`, so that all memory reached by it is considered to "not leak".
                 this.terminate_active_thread(TlsAllocAction::Leak)?;
 
-                // Machine cleanup. Only do this if all threads have terminated; threads that are still running
-                // might cause Stacked Borrows errors (https://github.com/rust-lang/miri/issues/2396).
-                if this.have_all_terminated() {
-                    // Even if all threads have terminated, we have to beware of data races since some threads
-                    // might not have joined the main thread (https://github.com/rust-lang/miri/issues/2020,
-                    // https://github.com/rust-lang/miri/issues/2508).
-                    this.allow_data_races_all_threads_done();
-                    EnvVars::cleanup(this).expect("error during env var cleanup");
-                }
-
                 // Stop interpreter loop.
                 throw_machine_stop!(TerminationInfo::Exit { code: exit_code, leak_check: true });
             }
@@ -443,7 +436,7 @@ pub fn create_ecx<'tcx>(
                     ImmTy::from_uint(sigpipe, ecx.machine.layouts.u8),
                 ],
                 Some(&ret_place),
-                StackPopCleanup::Root { cleanup: true },
+                ReturnContinuation::Stop { cleanup: true },
             )?;
         }
         MiriEntryFnType::MiriStart => {
@@ -452,7 +445,7 @@ pub fn create_ecx<'tcx>(
                 ExternAbi::Rust,
                 &[argc, argv],
                 Some(&ret_place),
-                StackPopCleanup::Root { cleanup: true },
+                ReturnContinuation::Stop { cleanup: true },
             )?;
         }
     }
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index fb34600fa37..c150dc16b07 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -162,7 +162,7 @@ pub fn iter_exported_symbols<'tcx>(
 
         // We can ignore `_export_info` here: we are a Rust crate, and everything is exported
         // from a Rust crate.
-        for &(symbol, _export_info) in tcx.exported_symbols(cnum) {
+        for &(symbol, _export_info) in tcx.exported_non_generic_symbols(cnum) {
             if let ExportedSymbol::NonGeneric(def_id) = symbol {
                 f(cnum, def_id)?;
             }
@@ -444,7 +444,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         caller_abi: ExternAbi,
         args: &[ImmTy<'tcx>],
         dest: Option<&MPlaceTy<'tcx>>,
-        stack_pop: StackPopCleanup,
+        cont: ReturnContinuation,
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
@@ -472,7 +472,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             &args.iter().map(|a| FnArg::Copy(a.clone().into())).collect::<Vec<_>>(),
             /*with_caller_location*/ false,
             &dest.into(),
-            stack_pop,
+            cont,
         )
     }
 
@@ -595,10 +595,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 } else if matches!(v.layout.fields, FieldsShape::Union(..)) {
                     // A (non-frozen) union. We fall back to whatever the type says.
                     (self.unsafe_cell_action)(v)
-                } else if matches!(v.layout.ty.kind(), ty::Dynamic(_, _, ty::DynStar)) {
-                    // This needs to read the vtable pointer to proceed type-driven, but we don't
-                    // want to reentrantly read from memory here.
-                    (self.unsafe_cell_action)(v)
                 } else {
                     // We want to not actually read from memory for this visit. So, before
                     // walking this value, we have to make sure it is not a
@@ -1337,7 +1333,6 @@ where
 
 /// Check that the number of varargs is at least the minimum what we expect.
 /// Fixed args should not be included.
-/// Use `check_vararg_fixed_arg_count` to extract the varargs slice from full function arguments.
 pub fn check_min_vararg_count<'a, 'tcx, const N: usize>(
     name: &'a str,
     args: &'a [OpTy<'tcx>],
diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs
index ec77a162cdb..4efa7dd4dcf 100644
--- a/src/tools/miri/src/intrinsics/mod.rs
+++ b/src/tools/miri/src/intrinsics/mod.rs
@@ -191,7 +191,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let [f] = check_intrinsic_arg_count(args)?;
                 let f = this.read_scalar(f)?.to_f32()?;
 
-                let res = fixed_float_value(intrinsic_name, &[f]).unwrap_or_else(||{
+                let res = fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| {
                     // Using host floats (but it's fine, these operations do not have
                     // guaranteed precision).
                     let host = f.to_host();
@@ -235,7 +235,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let [f] = check_intrinsic_arg_count(args)?;
                 let f = this.read_scalar(f)?.to_f64()?;
 
-                let res = fixed_float_value(intrinsic_name, &[f]).unwrap_or_else(||{
+                let res = fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| {
                     // Using host floats (but it's fine, these operations do not have
                     // guaranteed precision).
                     let host = f.to_host();
@@ -312,7 +312,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let f1 = this.read_scalar(f1)?.to_f32()?;
                 let f2 = this.read_scalar(f2)?.to_f32()?;
 
-                let res = fixed_float_value(intrinsic_name, &[f1, f2]).unwrap_or_else(|| {
+                let res = fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| {
                     // Using host floats (but it's fine, this operation does not have guaranteed precision).
                     let res = f1.to_host().powf(f2.to_host()).to_soft();
 
@@ -330,7 +330,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let f1 = this.read_scalar(f1)?.to_f64()?;
                 let f2 = this.read_scalar(f2)?.to_f64()?;
 
-                let res = fixed_float_value(intrinsic_name, &[f1, f2]).unwrap_or_else(|| {
+                let res = fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| {
                     // Using host floats (but it's fine, this operation does not have guaranteed precision).
                     let res = f1.to_host().powf(f2.to_host()).to_soft();
 
@@ -349,7 +349,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let f = this.read_scalar(f)?.to_f32()?;
                 let i = this.read_scalar(i)?.to_i32()?;
 
-                let res = fixed_powi_float_value(f, i).unwrap_or_else(|| {
+                let res = fixed_powi_float_value(this, f, i).unwrap_or_else(|| {
                     // Using host floats (but it's fine, this operation does not have guaranteed precision).
                     let res = f.to_host().powi(i).to_soft();
 
@@ -367,7 +367,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let f = this.read_scalar(f)?.to_f64()?;
                 let i = this.read_scalar(i)?.to_i32()?;
 
-                let res = fixed_powi_float_value(f, i).unwrap_or_else(|| {
+                let res = fixed_powi_float_value(this, f, i).unwrap_or_else(|| {
                     // Using host floats (but it's fine, this operation does not have guaranteed precision).
                     let res = f.to_host().powi(i).to_soft();
 
@@ -457,6 +457,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 throw_machine_stop!(TerminationInfo::Abort(format!("trace/breakpoint trap")))
             }
 
+            "assert_inhabited" | "assert_zero_valid" | "assert_mem_uninitialized_valid" => {
+                // Make these a NOP, so we get the better Miri-native error messages.
+            }
+
             _ => return interp_ok(EmulateItemResult::NotSupported),
         }
 
@@ -496,52 +500,88 @@ fn apply_random_float_error_to_imm<'tcx>(
 /// - logf32, logf64, log2f32, log2f64, log10f32, log10f64
 /// - powf32, powf64
 ///
+/// # Return
+///
 /// Returns `Some(output)` if the `intrinsic` results in a defined fixed `output` specified in the C standard
 /// (specifically, C23 annex F.10)  when given `args` as arguments. Outputs that are unaffected by a relative error
 /// (such as INF and zero) are not handled here, they are assumed to be handled by the underlying
 /// implementation. Returns `None` if no specific value is guaranteed.
+///
+/// # Note
+///
+/// For `powf*` operations of the form:
+///
+/// - `(SNaN)^(±0)`
+/// - `1^(SNaN)`
+///
+/// The result is implementation-defined:
+/// - musl returns for both `1.0`
+/// - glibc returns for both `NaN`
+///
+/// This discrepancy exists because SNaN handling is not consistently defined across platforms,
+/// and the C standard leaves behavior for SNaNs unspecified.
+///
+/// Miri chooses to adhere to both implementations and returns either one of them non-deterministically.
 fn fixed_float_value<S: Semantics>(
+    ecx: &mut MiriInterpCx<'_>,
     intrinsic_name: &str,
     args: &[IeeeFloat<S>],
 ) -> Option<IeeeFloat<S>> {
     let one = IeeeFloat::<S>::one();
-    match (intrinsic_name, args) {
+    Some(match (intrinsic_name, args) {
         // cos(+- 0) = 1
-        ("cosf32" | "cosf64", [input]) if input.is_zero() => Some(one),
+        ("cosf32" | "cosf64", [input]) if input.is_zero() => one,
 
         // e^0 = 1
-        ("expf32" | "expf64" | "exp2f32" | "exp2f64", [input]) if input.is_zero() => Some(one),
-
-        // 1^y = 1 for any y, even a NaN.
-        ("powf32" | "powf64", [base, _]) if *base == one => Some(one),
+        ("expf32" | "expf64" | "exp2f32" | "exp2f64", [input]) if input.is_zero() => one,
 
         // (-1)^(±INF) = 1
-        ("powf32" | "powf64", [base, exp]) if *base == -one && exp.is_infinite() => Some(one),
+        ("powf32" | "powf64", [base, exp]) if *base == -one && exp.is_infinite() => one,
+
+        // 1^y = 1 for any y, even a NaN
+        ("powf32" | "powf64", [base, exp]) if *base == one => {
+            let rng = ecx.machine.rng.get_mut();
+            // SNaN exponents get special treatment: they might return 1, or a NaN.
+            let return_nan = exp.is_signaling() && ecx.machine.float_nondet && rng.random();
+            // Handle both the musl and glibc cases non-deterministically.
+            if return_nan { ecx.generate_nan(args) } else { one }
+        }
 
-        // FIXME(#4286): The C ecosystem is inconsistent with handling sNaN's, some return 1 others propogate
-        // the NaN. We should return either 1 or the NaN non-deterministically here.
-        // But for now, just handle them all the same.
         // x^(±0) = 1 for any x, even a NaN
-        ("powf32" | "powf64", [_, exp]) if exp.is_zero() => Some(one),
+        ("powf32" | "powf64", [base, exp]) if exp.is_zero() => {
+            let rng = ecx.machine.rng.get_mut();
+            // SNaN bases get special treatment: they might return 1, or a NaN.
+            let return_nan = base.is_signaling() && ecx.machine.float_nondet && rng.random();
+            // Handle both the musl and glibc cases non-deterministically.
+            if return_nan { ecx.generate_nan(args) } else { one }
+        }
 
-        // There are a lot of cases for fixed outputs according to the C Standard, but these are mainly INF or zero
-        // which are not affected by the applied error.
-        _ => None,
-    }
+        // There are a lot of cases for fixed outputs according to the C Standard, but these are
+        // mainly INF or zero which are not affected by the applied error.
+        _ => return None,
+    })
 }
 
-/// Returns `Some(output)` if `powi` (called `pown` in C) results in a fixed value specified in the C standard
-/// (specifically, C23 annex F.10.4.6) when doing `base^exp`. Otherwise, returns `None`.
-fn fixed_powi_float_value<S: Semantics>(base: IeeeFloat<S>, exp: i32) -> Option<IeeeFloat<S>> {
-    match (base.category(), exp) {
-        // x^0 = 1, if x is not a Signaling NaN
-        // FIXME(#4286): The C ecosystem is inconsistent with handling sNaN's, some return 1 others propogate
-        // the NaN. We should return either 1 or the NaN non-deterministically here.
-        // But for now, just handle them all the same.
-        (_, 0) => Some(IeeeFloat::<S>::one()),
-
-        _ => None,
-    }
+/// Returns `Some(output)` if `powi` (called `pown` in C) results in a fixed value specified in the
+/// C standard (specifically, C23 annex F.10.4.6) when doing `base^exp`. Otherwise, returns `None`.
+fn fixed_powi_float_value<S: Semantics>(
+    ecx: &mut MiriInterpCx<'_>,
+    base: IeeeFloat<S>,
+    exp: i32,
+) -> Option<IeeeFloat<S>> {
+    Some(match exp {
+        0 => {
+            let one = IeeeFloat::<S>::one();
+            let rng = ecx.machine.rng.get_mut();
+            let return_nan = ecx.machine.float_nondet && rng.random() && base.is_signaling();
+            // For SNaN treatment, we are consistent with `powf`above.
+            // (We wouldn't have two, unlike powf all implementations seem to agree for powi,
+            // but for now we are maximally conservative.)
+            if return_nan { ecx.generate_nan(&[base]) } else { one }
+        }
+
+        _ => return None,
+    })
 }
 
 /// Given an floating-point operation and a floating-point value, clamps the result to the output
diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs
index 52224f33c73..e63992aa95f 100644
--- a/src/tools/miri/src/intrinsics/simd.rs
+++ b/src/tools/miri/src/intrinsics/simd.rs
@@ -36,6 +36,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             | "ceil"
             | "floor"
             | "round"
+            | "round_ties_even"
             | "trunc"
             | "fsqrt"
             | "fsin"
@@ -71,6 +72,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     "ceil" => Op::Round(rustc_apfloat::Round::TowardPositive),
                     "floor" => Op::Round(rustc_apfloat::Round::TowardNegative),
                     "round" => Op::Round(rustc_apfloat::Round::NearestTiesToAway),
+                    "round_ties_even" => Op::Round(rustc_apfloat::Round::NearestTiesToEven),
                     "trunc" => Op::Round(rustc_apfloat::Round::TowardZero),
                     "ctlz" => Op::Numeric(sym::ctlz),
                     "ctpop" => Op::Numeric(sym::ctpop),
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index e96c81d5b1d..c86e33e5185 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -1,5 +1,4 @@
-#![cfg_attr(bootstrap, feature(cfg_match))]
-#![cfg_attr(not(bootstrap), feature(cfg_select))]
+#![feature(cfg_select)]
 #![feature(rustc_private)]
 #![feature(float_gamma)]
 #![feature(float_erf)]
@@ -16,7 +15,6 @@
 #![feature(unqualified_local_imports)]
 #![feature(derive_coerce_pointee)]
 #![feature(arbitrary_self_types)]
-#![cfg_attr(bootstrap, feature(file_lock))]
 // Configure clippy and other lints
 #![allow(
     clippy::collapsible_else_if,
@@ -99,6 +97,11 @@ pub use rustc_const_eval::interpret::{self, AllocMap, Provenance as _};
 use rustc_middle::{bug, span_bug};
 use tracing::{info, trace};
 
+//#[cfg(target_os = "linux")]
+//pub mod native_lib {
+//    pub use crate::shims::{init_sv, register_retcode_sv};
+//}
+
 // Type aliases that set the provenance parameter.
 pub type Pointer = interpret::Pointer<Option<machine::Provenance>>;
 pub type StrictPointer = interpret::Pointer<machine::Provenance>;
@@ -122,10 +125,8 @@ pub use crate::concurrency::cpu_affinity::MAX_CPUS;
 pub use crate::concurrency::data_race::{
     AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, EvalContextExt as _,
 };
-pub use crate::concurrency::init_once::{EvalContextExt as _, InitOnceId};
-pub use crate::concurrency::sync::{
-    CondvarId, EvalContextExt as _, MutexRef, RwLockRef, SynchronizationObjects,
-};
+pub use crate::concurrency::init_once::{EvalContextExt as _, InitOnceRef};
+pub use crate::concurrency::sync::{CondvarRef, EvalContextExt as _, MutexRef, RwLockRef};
 pub use crate::concurrency::thread::{
     BlockReason, DynUnblockCallback, EvalContextExt as _, StackEmptyCallback, ThreadId,
     ThreadManager, TimeoutAnchor, TimeoutClock, UnblockKind,
@@ -168,7 +169,7 @@ pub const MIRI_DEFAULT_ARGS: &[&str] = &[
     "-Zmir-emit-retag",
     "-Zmir-preserve-ub",
     "-Zmir-opt-level=0",
-    "-Zmir-enable-passes=-CheckAlignment,-CheckNull",
+    "-Zmir-enable-passes=-CheckAlignment,-CheckNull,-CheckEnums",
     // Deduplicating diagnostics means we miss events when tracking what happens during an
     // execution. Let's not do that.
     "-Zdeduplicate-diagnostics=no",
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index b4d7db34efa..693b8916d89 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -130,11 +130,11 @@ pub enum MiriMemoryKind {
     WinHeap,
     /// Windows "local" memory (to be freed with `LocalFree`)
     WinLocal,
-    /// Memory for args, errno, and other parts of the machine-managed environment.
+    /// Memory for args, errno, env vars, and other parts of the machine-managed environment.
     /// This memory may leak.
     Machine,
-    /// Memory allocated by the runtime (e.g. env vars). Separate from `Machine`
-    /// because we clean it up and leak-check it.
+    /// Memory allocated by the runtime, e.g. for readdir. Separate from `Machine` because we clean
+    /// it up (or expect the user to invoke operations that clean it up) and leak-check it.
     Runtime,
     /// Globals copied from `tcx`.
     /// This memory may leak.
@@ -285,7 +285,7 @@ impl interpret::Provenance for Provenance {
     }
 
     fn fmt(ptr: &interpret::Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let (prov, addr) = ptr.into_parts(); // address is absolute
+        let (prov, addr) = ptr.into_raw_parts(); // offset is absolute address
         write!(f, "{:#x}", addr.bytes())?;
         if f.alternate() {
             write!(f, "{prov:#?}")?;
@@ -499,9 +499,6 @@ pub struct MiriMachine<'tcx> {
     /// in `sched_getaffinity`
     pub(crate) thread_cpu_affinity: FxHashMap<ThreadId, CpuAffinityMask>,
 
-    /// The state of the primitive synchronization objects.
-    pub(crate) sync: SynchronizationObjects,
-
     /// Precomputed `TyLayout`s for primitive data types that are commonly used inside Miri.
     pub(crate) layouts: PrimitiveLayouts<'tcx>,
 
@@ -713,7 +710,6 @@ impl<'tcx> MiriMachine<'tcx> {
             layouts,
             threads,
             thread_cpu_affinity,
-            sync: SynchronizationObjects::default(),
             static_roots: Vec::new(),
             profiler,
             string_cache: Default::default(),
@@ -903,7 +899,6 @@ impl VisitProvenance for MiriMachine<'_> {
         let MiriMachine {
             threads,
             thread_cpu_affinity: _,
-            sync: _,
             tls,
             env_vars,
             main_fn_ret_place,
@@ -1019,6 +1014,8 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
 
     const PANIC_ON_ALLOC_FAIL: bool = false;
 
+    const TRACING_ENABLED: bool = cfg!(feature = "tracing");
+
     #[inline(always)]
     fn enforce_alignment(ecx: &MiriInterpCx<'tcx>) -> bool {
         ecx.machine.check_alignment != AlignmentCheck::None
@@ -1056,7 +1053,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             // What's the offset between us and the promised alignment?
             let distance = offset.bytes().wrapping_sub(promised_offset.bytes());
             // That must also be aligned.
-            if distance % align.bytes() == 0 {
+            if distance.is_multiple_of(align.bytes()) {
                 // All looking good!
                 None
             } else {
@@ -1202,7 +1199,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             ExternAbi::Rust,
             &[],
             None,
-            StackPopCleanup::Goto { ret: None, unwind: mir::UnwindAction::Unreachable },
+            ReturnContinuation::Goto { ret: None, unwind: mir::UnwindAction::Unreachable },
         )?;
         interp_ok(())
     }
@@ -1612,7 +1609,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         ecx.machine.since_gc += 1;
         // Possibly report our progress. This will point at the terminator we are about to execute.
         if let Some(report_progress) = ecx.machine.report_progress {
-            if ecx.machine.basic_block_count % u64::from(report_progress) == 0 {
+            if ecx.machine.basic_block_count.is_multiple_of(u64::from(report_progress)) {
                 ecx.emit_diagnostic(NonHaltingDiagnostic::ProgressReport {
                     block_count: ecx.machine.basic_block_count,
                 });
diff --git a/src/tools/miri/src/provenance_gc.rs b/src/tools/miri/src/provenance_gc.rs
index b3d715db9cd..6adf1448648 100644
--- a/src/tools/miri/src/provenance_gc.rs
+++ b/src/tools/miri/src/provenance_gc.rs
@@ -68,15 +68,13 @@ impl VisitProvenance for Provenance {
 
 impl VisitProvenance for StrictPointer {
     fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
-        let (prov, _offset) = self.into_parts();
-        prov.visit_provenance(visit);
+        self.provenance.visit_provenance(visit);
     }
 }
 
 impl VisitProvenance for Pointer {
     fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
-        let (prov, _offset) = self.into_parts();
-        prov.visit_provenance(visit);
+        self.provenance.visit_provenance(visit);
     }
 }
 
diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs
index dd00b270b38..18d60915d20 100644
--- a/src/tools/miri/src/shims/backtrace.rs
+++ b/src/tools/miri/src/shims/backtrace.rs
@@ -104,7 +104,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.tcx.sess.source_map().lookup_char_pos(BytePos(offset.bytes().try_into().unwrap()));
 
         let name = fn_instance.to_string();
-        let filename = lo.file.name.prefer_remapped_unconditionaly().to_string();
+        let filename = lo.file.name.prefer_remapped_unconditionally().to_string();
 
         interp_ok((fn_instance, lo, name, filename))
     }
diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs
index e99a8fd6e8c..689cd3a7269 100644
--- a/src/tools/miri/src/shims/env.rs
+++ b/src/tools/miri/src/shims/env.rs
@@ -59,15 +59,6 @@ impl<'tcx> EnvVars<'tcx> {
         interp_ok(())
     }
 
-    pub(crate) fn cleanup(ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>) -> InterpResult<'tcx> {
-        let this = ecx.eval_context_mut();
-        match this.machine.env_vars {
-            EnvVars::Unix(_) => UnixEnvVars::cleanup(this),
-            EnvVars::Windows(_) => interp_ok(()), // no cleanup needed
-            EnvVars::Uninit => interp_ok(()),
-        }
-    }
-
     pub(crate) fn unix(&self) -> &UnixEnvVars<'tcx> {
         match self {
             EnvVars::Unix(env) => env,
@@ -110,8 +101,30 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         }
     }
 
+    /// Get the process identifier.
     fn get_pid(&self) -> u32 {
         let this = self.eval_context_ref();
         if this.machine.communicate() { std::process::id() } else { 1000 }
     }
+
+    /// Get an "OS" thread ID for the current thread.
+    fn get_current_tid(&self) -> u32 {
+        let this = self.eval_context_ref();
+        self.get_tid(this.machine.threads.active_thread())
+    }
+
+    /// Get an "OS" thread ID for any thread.
+    fn get_tid(&self, thread: ThreadId) -> u32 {
+        let this = self.eval_context_ref();
+        let index = thread.to_u32();
+        let target_os = &this.tcx.sess.target.os;
+        if target_os == "linux" || target_os == "netbsd" {
+            // On Linux, the main thread has PID == TID so we uphold this. NetBSD also appears
+            // to exhibit the same behavior, though I can't find a citation.
+            this.get_pid().strict_add(index)
+        } else {
+            // Other platforms do not display any relationship between PID and TID.
+            index
+        }
+    }
 }
diff --git a/src/tools/miri/src/shims/extern_static.rs b/src/tools/miri/src/shims/extern_static.rs
index a2ea3dbd88b..49c0c380a08 100644
--- a/src/tools/miri/src/shims/extern_static.rs
+++ b/src/tools/miri/src/shims/extern_static.rs
@@ -1,7 +1,5 @@
 //! Provides the `extern static` that this platform expects.
 
-use rustc_symbol_mangling::mangle_internal_symbol;
-
 use crate::*;
 
 impl<'tcx> MiriMachine<'tcx> {
@@ -45,15 +43,6 @@ impl<'tcx> MiriMachine<'tcx> {
 
     /// Sets up the "extern statics" for this machine.
     pub fn init_extern_statics(ecx: &mut MiriInterpCx<'tcx>) -> InterpResult<'tcx> {
-        // "__rust_alloc_error_handler_should_panic"
-        let val = ecx.tcx.sess.opts.unstable_opts.oom.should_panic();
-        let val = ImmTy::from_int(val, ecx.machine.layouts.u8);
-        Self::alloc_extern_static(
-            ecx,
-            &mangle_internal_symbol(*ecx.tcx, "__rust_alloc_error_handler_should_panic"),
-            val,
-        )?;
-
         if ecx.target_os_is_unix() {
             // "environ" is mandated by POSIX.
             let environ = ecx.machine.env_vars.unix().environ();
@@ -66,7 +55,7 @@ impl<'tcx> MiriMachine<'tcx> {
                     ecx,
                     &["__cxa_thread_atexit_impl", "__clock_gettime64"],
                 )?;
-                Self::weak_symbol_extern_statics(ecx, &["getrandom", "statx"])?;
+                Self::weak_symbol_extern_statics(ecx, &["getrandom", "gettid", "statx"])?;
             }
             "freebsd" => {
                 Self::null_ptr_extern_statics(ecx, &["__cxa_thread_atexit_impl"])?;
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index 416cb1ab55e..9ddba8c2b48 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -411,7 +411,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         AlignFromBytesError::TooLarge(_) => Align::MAX,
                     }
                 });
-                let (_, addr) = ptr.into_parts(); // we know the offset is absolute
+                let addr = ptr.addr();
                 // Cannot panic since `align` is a power of 2 and hence non-zero.
                 if addr.bytes().strict_rem(align.bytes()) != 0 {
                     throw_unsup_format!(
@@ -615,6 +615,14 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // This is a no-op shim that only exists to prevent making the allocator shims instantly stable.
                 let [] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
             }
+            name if name
+                == this.mangle_internal_symbol("__rust_alloc_error_handler_should_panic_v2") =>
+            {
+                // Gets the value of the `oom` option.
+                let [] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
+                let val = this.tcx.sess.opts.unstable_opts.oom.should_panic();
+                this.write_int(val, dest)?;
+            }
 
             // C memory handling functions
             "memcmp" => {
diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs
index b498551ace3..f09fc546b3e 100644
--- a/src/tools/miri/src/shims/mod.rs
+++ b/src/tools/miri/src/shims/mod.rs
@@ -21,6 +21,8 @@ pub mod time;
 pub mod tls;
 
 pub use self::files::FdTable;
+//#[cfg(target_os = "linux")]
+//pub use self::native_lib::trace::{init_sv, register_retcode_sv};
 pub use self::unix::{DirTable, EpollInterestTable};
 
 /// What needs to be done after emulating an item (a shim or an intrinsic) is done.
diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib/mod.rs
index 030c2e36721..9b30d8ce78b 100644
--- a/src/tools/miri/src/shims/native_lib.rs
+++ b/src/tools/miri/src/shims/native_lib/mod.rs
@@ -1,4 +1,9 @@
 //! Implements calling functions from a native library.
+
+// FIXME: disabled since it fails to build on many targets.
+//#[cfg(target_os = "linux")]
+//pub mod trace;
+
 use std::ops::Deref;
 
 use libffi::high::call as ffi;
@@ -8,8 +13,15 @@ use rustc_middle::mir::interpret::Pointer;
 use rustc_middle::ty::{self as ty, IntTy, UintTy};
 use rustc_span::Symbol;
 
+//#[cfg(target_os = "linux")]
+//use self::trace::Supervisor;
 use crate::*;
 
+//#[cfg(target_os = "linux")]
+//type CallResult<'tcx> = InterpResult<'tcx, (ImmTy<'tcx>, Option<self::trace::messages::MemEvents>)>;
+//#[cfg(not(target_os = "linux"))]
+type CallResult<'tcx> = InterpResult<'tcx, (ImmTy<'tcx>, Option<!>)>;
+
 impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
 trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
     /// Call native host function and return the output as an immediate.
@@ -19,71 +31,93 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
         dest: &MPlaceTy<'tcx>,
         ptr: CodePtr,
         libffi_args: Vec<libffi::high::Arg<'a>>,
-    ) -> InterpResult<'tcx, ImmTy<'tcx>> {
+    ) -> CallResult<'tcx> {
         let this = self.eval_context_mut();
+        //#[cfg(target_os = "linux")]
+        //let alloc = this.machine.allocator.as_ref().unwrap();
+
+        // SAFETY: We don't touch the machine memory past this point.
+        //#[cfg(target_os = "linux")]
+        //let (guard, stack_ptr) = unsafe { Supervisor::start_ffi(alloc) };
 
         // Call the function (`ptr`) with arguments `libffi_args`, and obtain the return value
         // as the specified primitive integer type
-        let scalar = match dest.layout.ty.kind() {
-            // ints
-            ty::Int(IntTy::I8) => {
-                // Unsafe because of the call to native code.
-                // Because this is calling a C function it is not necessarily sound,
-                // but there is no way around this and we've checked as much as we can.
-                let x = unsafe { ffi::call::<i8>(ptr, libffi_args.as_slice()) };
-                Scalar::from_i8(x)
-            }
-            ty::Int(IntTy::I16) => {
-                let x = unsafe { ffi::call::<i16>(ptr, libffi_args.as_slice()) };
-                Scalar::from_i16(x)
-            }
-            ty::Int(IntTy::I32) => {
-                let x = unsafe { ffi::call::<i32>(ptr, libffi_args.as_slice()) };
-                Scalar::from_i32(x)
-            }
-            ty::Int(IntTy::I64) => {
-                let x = unsafe { ffi::call::<i64>(ptr, libffi_args.as_slice()) };
-                Scalar::from_i64(x)
-            }
-            ty::Int(IntTy::Isize) => {
-                let x = unsafe { ffi::call::<isize>(ptr, libffi_args.as_slice()) };
-                Scalar::from_target_isize(x.try_into().unwrap(), this)
-            }
-            // uints
-            ty::Uint(UintTy::U8) => {
-                let x = unsafe { ffi::call::<u8>(ptr, libffi_args.as_slice()) };
-                Scalar::from_u8(x)
-            }
-            ty::Uint(UintTy::U16) => {
-                let x = unsafe { ffi::call::<u16>(ptr, libffi_args.as_slice()) };
-                Scalar::from_u16(x)
-            }
-            ty::Uint(UintTy::U32) => {
-                let x = unsafe { ffi::call::<u32>(ptr, libffi_args.as_slice()) };
-                Scalar::from_u32(x)
-            }
-            ty::Uint(UintTy::U64) => {
-                let x = unsafe { ffi::call::<u64>(ptr, libffi_args.as_slice()) };
-                Scalar::from_u64(x)
-            }
-            ty::Uint(UintTy::Usize) => {
-                let x = unsafe { ffi::call::<usize>(ptr, libffi_args.as_slice()) };
-                Scalar::from_target_usize(x.try_into().unwrap(), this)
-            }
-            // Functions with no declared return type (i.e., the default return)
-            // have the output_type `Tuple([])`.
-            ty::Tuple(t_list) if (*t_list).deref().is_empty() => {
-                unsafe { ffi::call::<()>(ptr, libffi_args.as_slice()) };
-                return interp_ok(ImmTy::uninit(dest.layout));
-            }
-            ty::RawPtr(..) => {
-                let x = unsafe { ffi::call::<*const ()>(ptr, libffi_args.as_slice()) };
-                let ptr = Pointer::new(Provenance::Wildcard, Size::from_bytes(x.addr()));
-                Scalar::from_pointer(ptr, this)
-            }
-            _ => throw_unsup_format!("unsupported return type for native call: {:?}", link_name),
+        let res = 'res: {
+            let scalar = match dest.layout.ty.kind() {
+                // ints
+                ty::Int(IntTy::I8) => {
+                    // Unsafe because of the call to native code.
+                    // Because this is calling a C function it is not necessarily sound,
+                    // but there is no way around this and we've checked as much as we can.
+                    let x = unsafe { ffi::call::<i8>(ptr, libffi_args.as_slice()) };
+                    Scalar::from_i8(x)
+                }
+                ty::Int(IntTy::I16) => {
+                    let x = unsafe { ffi::call::<i16>(ptr, libffi_args.as_slice()) };
+                    Scalar::from_i16(x)
+                }
+                ty::Int(IntTy::I32) => {
+                    let x = unsafe { ffi::call::<i32>(ptr, libffi_args.as_slice()) };
+                    Scalar::from_i32(x)
+                }
+                ty::Int(IntTy::I64) => {
+                    let x = unsafe { ffi::call::<i64>(ptr, libffi_args.as_slice()) };
+                    Scalar::from_i64(x)
+                }
+                ty::Int(IntTy::Isize) => {
+                    let x = unsafe { ffi::call::<isize>(ptr, libffi_args.as_slice()) };
+                    Scalar::from_target_isize(x.try_into().unwrap(), this)
+                }
+                // uints
+                ty::Uint(UintTy::U8) => {
+                    let x = unsafe { ffi::call::<u8>(ptr, libffi_args.as_slice()) };
+                    Scalar::from_u8(x)
+                }
+                ty::Uint(UintTy::U16) => {
+                    let x = unsafe { ffi::call::<u16>(ptr, libffi_args.as_slice()) };
+                    Scalar::from_u16(x)
+                }
+                ty::Uint(UintTy::U32) => {
+                    let x = unsafe { ffi::call::<u32>(ptr, libffi_args.as_slice()) };
+                    Scalar::from_u32(x)
+                }
+                ty::Uint(UintTy::U64) => {
+                    let x = unsafe { ffi::call::<u64>(ptr, libffi_args.as_slice()) };
+                    Scalar::from_u64(x)
+                }
+                ty::Uint(UintTy::Usize) => {
+                    let x = unsafe { ffi::call::<usize>(ptr, libffi_args.as_slice()) };
+                    Scalar::from_target_usize(x.try_into().unwrap(), this)
+                }
+                // Functions with no declared return type (i.e., the default return)
+                // have the output_type `Tuple([])`.
+                ty::Tuple(t_list) if (*t_list).deref().is_empty() => {
+                    unsafe { ffi::call::<()>(ptr, libffi_args.as_slice()) };
+                    break 'res interp_ok(ImmTy::uninit(dest.layout));
+                }
+                ty::RawPtr(..) => {
+                    let x = unsafe { ffi::call::<*const ()>(ptr, libffi_args.as_slice()) };
+                    let ptr = Pointer::new(Provenance::Wildcard, Size::from_bytes(x.addr()));
+                    Scalar::from_pointer(ptr, this)
+                }
+                _ =>
+                    break 'res Err(err_unsup_format!(
+                        "unsupported return type for native call: {:?}",
+                        link_name
+                    ))
+                    .into(),
+            };
+            interp_ok(ImmTy::from_scalar(scalar, dest.layout))
         };
-        interp_ok(ImmTy::from_scalar(scalar, dest.layout))
+
+        // SAFETY: We got the guard and stack pointer from start_ffi, and
+        // the allocator is the same
+        //#[cfg(target_os = "linux")]
+        //let events = unsafe { Supervisor::end_ffi(alloc, guard, stack_ptr) };
+        //#[cfg(not(target_os = "linux"))]
+        let events = None;
+
+        interp_ok((res?, events))
     }
 
     /// Get the pointer to the function of the specified name in the shared object file,
@@ -164,7 +198,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let mut libffi_args = Vec::<CArg>::with_capacity(args.len());
         for arg in args.iter() {
             if !matches!(arg.layout.backend_repr, BackendRepr::Scalar(_)) {
-                throw_unsup_format!("only scalar argument types are support for native calls")
+                throw_unsup_format!("only scalar argument types are supported for native calls")
             }
             let imm = this.read_immediate(arg)?;
             libffi_args.push(imm_to_carg(&imm, this)?);
@@ -179,24 +213,63 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // The first time this happens, print a warning.
                 if !this.machine.native_call_mem_warned.replace(true) {
                     // Newly set, so first time we get here.
-                    this.emit_diagnostic(NonHaltingDiagnostic::NativeCallSharedMem);
+                    this.emit_diagnostic(NonHaltingDiagnostic::NativeCallSharedMem {
+                        //#[cfg(target_os = "linux")]
+                        //tracing: self::trace::Supervisor::is_enabled(),
+                        //#[cfg(not(target_os = "linux"))]
+                        tracing: false,
+                    });
                 }
 
                 this.expose_provenance(prov)?;
             }
         }
-
-        // Prepare all exposed memory.
-        this.prepare_exposed_for_native_call()?;
-
-        // Convert them to `libffi::high::Arg` type.
+        // Convert arguments to `libffi::high::Arg` type.
         let libffi_args = libffi_args
             .iter()
             .map(|arg| arg.arg_downcast())
             .collect::<Vec<libffi::high::Arg<'_>>>();
 
+        // Prepare all exposed memory (both previously exposed, and just newly exposed since a
+        // pointer was passed as argument).
+        this.visit_reachable_allocs(this.exposed_allocs(), |this, alloc_id, info| {
+            // If there is no data behind this pointer, skip this.
+            if !matches!(info.kind, AllocKind::LiveData) {
+                return interp_ok(());
+            }
+            // It's okay to get raw access, what we do does not correspond to any actual
+            // AM operation, it just approximates the state to account for the native call.
+            let alloc = this.get_alloc_raw(alloc_id)?;
+            // Also expose the provenance of the interpreter-level allocation, so it can
+            // be read by FFI. The `black_box` is defensive programming as LLVM likes
+            // to (incorrectly) optimize away ptr2int casts whose result is unused.
+            std::hint::black_box(alloc.get_bytes_unchecked_raw().expose_provenance());
+            // Expose all provenances in this allocation, since the native code can do $whatever.
+            for prov in alloc.provenance().provenances() {
+                this.expose_provenance(prov)?;
+            }
+
+            // Prepare for possible write from native code if mutable.
+            if info.mutbl.is_mut() {
+                let alloc = &mut this.get_alloc_raw_mut(alloc_id)?.0;
+                alloc.prepare_for_native_access();
+                // Also expose *mutable* provenance for the interpreter-level allocation.
+                std::hint::black_box(alloc.get_bytes_unchecked_raw_mut().expose_provenance());
+            }
+
+            interp_ok(())
+        })?;
+
         // Call the function and store output, depending on return type in the function signature.
-        let ret = this.call_native_with_args(link_name, dest, code_ptr, libffi_args)?;
+        let (ret, maybe_memevents) =
+            this.call_native_with_args(link_name, dest, code_ptr, libffi_args)?;
+
+        if cfg!(target_os = "linux")
+            && let Some(events) = maybe_memevents
+        {
+            trace!("Registered FFI events:\n{events:#0x?}");
+        }
+
         this.write_immediate(*ret, dest)?;
         interp_ok(true)
     }
@@ -274,7 +347,8 @@ fn imm_to_carg<'tcx>(v: &ImmTy<'tcx>, cx: &impl HasDataLayout) -> InterpResult<'
             CArg::USize(v.to_scalar().to_target_usize(cx)?.try_into().unwrap()),
         ty::RawPtr(..) => {
             let s = v.to_scalar().to_pointer(cx)?.addr();
-            // This relies on the `expose_provenance` in `prepare_for_native_call`.
+            // This relies on the `expose_provenance` in the `visit_reachable_allocs` callback
+            // above.
             CArg::RawPtr(std::ptr::with_exposed_provenance_mut(s.bytes_usize()))
         }
         _ => throw_unsup_format!("unsupported argument type for native call: {}", v.layout.ty),
diff --git a/src/tools/miri/src/shims/native_lib/trace/child.rs b/src/tools/miri/src/shims/native_lib/trace/child.rs
new file mode 100644
index 00000000000..4961e875c77
--- /dev/null
+++ b/src/tools/miri/src/shims/native_lib/trace/child.rs
@@ -0,0 +1,251 @@
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use ipc_channel::ipc;
+use nix::sys::{ptrace, signal};
+use nix::unistd;
+
+use super::CALLBACK_STACK_SIZE;
+use super::messages::{Confirmation, MemEvents, StartFfiInfo, TraceRequest};
+use super::parent::{ChildListener, sv_loop};
+use crate::alloc::isolated_alloc::IsolatedAlloc;
+
+static SUPERVISOR: std::sync::Mutex<Option<Supervisor>> = std::sync::Mutex::new(None);
+
+/// The main means of communication between the child and parent process,
+/// allowing the former to send requests and get info from the latter.
+pub struct Supervisor {
+    /// Sender for FFI-mode-related requests.
+    message_tx: ipc::IpcSender<TraceRequest>,
+    /// Used for synchronisation, allowing us to receive confirmation that the
+    /// parent process has handled the request from `message_tx`.
+    confirm_rx: ipc::IpcReceiver<Confirmation>,
+    /// Receiver for memory acceses that ocurred during the FFI call.
+    event_rx: ipc::IpcReceiver<MemEvents>,
+}
+
+/// Marker representing that an error occurred during creation of the supervisor.
+#[derive(Debug)]
+pub struct SvInitError;
+
+impl Supervisor {
+    /// Returns `true` if the supervisor process exists, and `false` otherwise.
+    pub fn is_enabled() -> bool {
+        SUPERVISOR.lock().unwrap().is_some()
+    }
+
+    /// Begins preparations for doing an FFI call. This should be called at
+    /// the last possible moment before entering said call. `alloc` points to
+    /// the allocator which handed out the memory used for this machine.
+    ///
+    /// As this locks the supervisor via a mutex, no other threads may enter FFI
+    /// until this one returns and its guard is dropped via `end_ffi`. The
+    /// pointer returned should be passed to `end_ffi` to avoid a memory leak.
+    ///
+    /// SAFETY: The resulting guard must be dropped *via `end_ffi`* immediately
+    /// after the desired call has concluded.
+    pub unsafe fn start_ffi(
+        alloc: &Rc<RefCell<IsolatedAlloc>>,
+    ) -> (std::sync::MutexGuard<'static, Option<Supervisor>>, Option<*mut [u8; CALLBACK_STACK_SIZE]>)
+    {
+        let mut sv_guard = SUPERVISOR.lock().unwrap();
+        // If the supervisor is not initialised for whatever reason, fast-fail.
+        // This might be desired behaviour, as even on platforms where ptracing
+        // is not implemented it enables us to enforce that only one FFI call
+        // happens at a time.
+        let Some(sv) = sv_guard.take() else {
+            return (sv_guard, None);
+        };
+
+        // Get pointers to all the pages the supervisor must allow accesses in
+        // and prepare the callback stack.
+        let page_ptrs = alloc.borrow().pages();
+        let raw_stack_ptr: *mut [u8; CALLBACK_STACK_SIZE] =
+            Box::leak(Box::new([0u8; CALLBACK_STACK_SIZE])).as_mut_ptr().cast();
+        let stack_ptr = raw_stack_ptr.expose_provenance();
+        let start_info = StartFfiInfo { page_ptrs, stack_ptr };
+
+        // SAFETY: We do not access machine memory past this point until the
+        // supervisor is ready to allow it.
+        unsafe {
+            if alloc.borrow_mut().prepare_ffi().is_err() {
+                // Don't mess up unwinding by maybe leaving the memory partly protected
+                alloc.borrow_mut().unprep_ffi();
+                panic!("Cannot protect memory for FFI call!");
+            }
+        }
+
+        // Send over the info.
+        // NB: if we do not wait to receive a blank confirmation response, it is
+        // possible that the supervisor is alerted of the SIGSTOP *before* it has
+        // actually received the start_info, thus deadlocking! This way, we can
+        // enforce an ordering for these events.
+        sv.message_tx.send(TraceRequest::StartFfi(start_info)).unwrap();
+        sv.confirm_rx.recv().unwrap();
+        *sv_guard = Some(sv);
+        // We need to be stopped for the supervisor to be able to make certain
+        // modifications to our memory - simply waiting on the recv() doesn't
+        // count.
+        signal::raise(signal::SIGSTOP).unwrap();
+        (sv_guard, Some(raw_stack_ptr))
+    }
+
+    /// Undoes FFI-related preparations, allowing Miri to continue as normal, then
+    /// gets the memory accesses and changes performed during the FFI call. Note
+    /// that this may include some spurious accesses done by `libffi` itself in
+    /// the process of executing the function call.
+    ///
+    /// SAFETY: The `sv_guard` and `raw_stack_ptr` passed must be the same ones
+    /// received by a prior call to `start_ffi`, and the allocator must be the
+    /// one passed to it also.
+    pub unsafe fn end_ffi(
+        alloc: &Rc<RefCell<IsolatedAlloc>>,
+        mut sv_guard: std::sync::MutexGuard<'static, Option<Supervisor>>,
+        raw_stack_ptr: Option<*mut [u8; CALLBACK_STACK_SIZE]>,
+    ) -> Option<MemEvents> {
+        // We can't use IPC channels here to signal that FFI mode has ended,
+        // since they might allocate memory which could get us stuck in a SIGTRAP
+        // with no easy way out! While this could be worked around, it is much
+        // simpler and more robust to simply use the signals which are left for
+        // arbitrary usage. Since this will block until we are continued by the
+        // supervisor, we can assume past this point that everything is back to
+        // normal.
+        signal::raise(signal::SIGUSR1).unwrap();
+
+        // This is safe! It just sets memory to normal expected permissions.
+        alloc.borrow_mut().unprep_ffi();
+
+        // If this is `None`, then `raw_stack_ptr` is None and does not need to
+        // be deallocated (and there's no need to worry about the guard, since
+        // it contains nothing).
+        let sv = sv_guard.take()?;
+        // SAFETY: Caller upholds that this pointer was allocated as a box with
+        // this type.
+        unsafe {
+            drop(Box::from_raw(raw_stack_ptr.unwrap()));
+        }
+        // On the off-chance something really weird happens, don't block forever.
+        let ret = sv
+            .event_rx
+            .try_recv_timeout(std::time::Duration::from_secs(5))
+            .map_err(|e| {
+                match e {
+                    ipc::TryRecvError::IpcError(_) => (),
+                    ipc::TryRecvError::Empty =>
+                        eprintln!("Waiting for accesses from supervisor timed out!"),
+                }
+            })
+            .ok();
+        // Do *not* leave the supervisor empty, or else we might get another fork...
+        *sv_guard = Some(sv);
+        ret
+    }
+}
+
+/// Initialises the supervisor process. If this function errors, then the
+/// supervisor process could not be created successfully; else, the caller
+/// is now the child process and can communicate via `start_ffi`/`end_ffi`,
+/// receiving back events through `get_events`.
+///
+/// # Safety
+/// The invariants for `fork()` must be upheld by the caller.
+pub unsafe fn init_sv() -> Result<(), SvInitError> {
+    // FIXME: Much of this could be reimplemented via the mitosis crate if we upstream the
+    // relevant missing bits.
+
+    // On Linux, this will check whether ptrace is fully disabled by the Yama module.
+    // If Yama isn't running or we're not on Linux, we'll still error later, but
+    // this saves a very expensive fork call.
+    let ptrace_status = std::fs::read_to_string("/proc/sys/kernel/yama/ptrace_scope");
+    if let Ok(stat) = ptrace_status {
+        if let Some(stat) = stat.chars().next() {
+            // Fast-error if ptrace is fully disabled on the system.
+            if stat == '3' {
+                return Err(SvInitError);
+            }
+        }
+    }
+
+    // Initialise the supervisor if it isn't already, placing it into SUPERVISOR.
+    let mut lock = SUPERVISOR.lock().unwrap();
+    if lock.is_some() {
+        return Ok(());
+    }
+
+    // Prepare the IPC channels we need.
+    let (message_tx, message_rx) = ipc::channel().unwrap();
+    let (confirm_tx, confirm_rx) = ipc::channel().unwrap();
+    let (event_tx, event_rx) = ipc::channel().unwrap();
+    // SAFETY: Calling sysconf(_SC_PAGESIZE) is always safe and cannot error.
+    let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) }.try_into().unwrap();
+    super::parent::PAGE_SIZE.store(page_size, std::sync::atomic::Ordering::Relaxed);
+
+    unsafe {
+        // TODO: Maybe use clone3() instead for better signalling of when the child exits?
+        // SAFETY: Caller upholds that only one thread exists.
+        match unistd::fork().unwrap() {
+            unistd::ForkResult::Parent { child } => {
+                // If somehow another thread does exist, prevent it from accessing the lock
+                // and thus breaking our safety invariants.
+                std::mem::forget(lock);
+                // The child process is free to unwind, so we won't to avoid doubly freeing
+                // system resources.
+                let init = std::panic::catch_unwind(|| {
+                    let listener =
+                        ChildListener { message_rx, attached: false, override_retcode: None };
+                    // Trace as many things as possible, to be able to handle them as needed.
+                    let options = ptrace::Options::PTRACE_O_TRACESYSGOOD
+                        | ptrace::Options::PTRACE_O_TRACECLONE
+                        | ptrace::Options::PTRACE_O_TRACEFORK;
+                    // Attach to the child process without stopping it.
+                    match ptrace::seize(child, options) {
+                        // Ptrace works :D
+                        Ok(_) => {
+                            let code = sv_loop(listener, child, event_tx, confirm_tx).unwrap_err();
+                            // If a return code of 0 is not explicitly given, assume something went
+                            // wrong and return 1.
+                            std::process::exit(code.0.unwrap_or(1))
+                        }
+                        // Ptrace does not work and we failed to catch that.
+                        Err(_) => {
+                            // If we can't ptrace, Miri continues being the parent.
+                            signal::kill(child, signal::SIGKILL).unwrap();
+                            SvInitError
+                        }
+                    }
+                });
+                match init {
+                    // The "Ok" case means that we couldn't ptrace.
+                    Ok(e) => return Err(e),
+                    Err(p) => {
+                        eprintln!("Supervisor process panicked!\n{p:?}");
+                        std::process::exit(1);
+                    }
+                }
+            }
+            unistd::ForkResult::Child => {
+                // Make sure we never get orphaned and stuck in SIGSTOP or similar
+                // SAFETY: prctl PR_SET_PDEATHSIG is always safe to call.
+                let ret = libc::prctl(libc::PR_SET_PDEATHSIG, libc::SIGTERM);
+                assert_eq!(ret, 0);
+                // First make sure the parent succeeded with ptracing us!
+                signal::raise(signal::SIGSTOP).unwrap();
+                // If we're the child process, save the supervisor info.
+                *lock = Some(Supervisor { message_tx, confirm_rx, event_rx });
+            }
+        }
+    }
+    Ok(())
+}
+
+/// Instruct the supervisor process to return a particular code. Useful if for
+/// whatever reason this code fails to be intercepted normally. In the case of
+/// `abort_if_errors()` used in `bin/miri.rs`, the return code is erroneously
+/// given as a 0 if this is not used.
+pub fn register_retcode_sv(code: i32) {
+    let mut sv_guard = SUPERVISOR.lock().unwrap();
+    if let Some(sv) = sv_guard.take() {
+        sv.message_tx.send(TraceRequest::OverrideRetcode(code)).unwrap();
+        *sv_guard = Some(sv);
+    }
+}
diff --git a/src/tools/miri/src/shims/native_lib/trace/messages.rs b/src/tools/miri/src/shims/native_lib/trace/messages.rs
new file mode 100644
index 00000000000..8a83dab5c09
--- /dev/null
+++ b/src/tools/miri/src/shims/native_lib/trace/messages.rs
@@ -0,0 +1,80 @@
+//! Houses the types that are directly sent across the IPC channels.
+//!
+//! The overall structure of a traced FFI call, from the child process's POV, is
+//! as follows:
+//! ```
+//! message_tx.send(TraceRequest::StartFfi);
+//! confirm_rx.recv();
+//! raise(SIGSTOP);
+//! /* do ffi call */
+//! raise(SIGUSR1); // morally equivalent to some kind of "TraceRequest::EndFfi"
+//! let events = event_rx.recv();
+//! ```
+//! `TraceRequest::OverrideRetcode` can be sent at any point in the above, including
+//! before or after all of them.
+//!
+//! NB: sending these events out of order, skipping steps, etc. will result in
+//! unspecified behaviour from the supervisor process, so use the abstractions
+//! in `super::child` (namely `start_ffi()` and `end_ffi()`) to handle this. It is
+//! trivially easy to cause a deadlock or crash by messing this up!
+
+use std::ops::Range;
+
+/// An IPC request sent by the child process to the parent.
+///
+/// The sender for this channel should live on the child process.
+#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
+pub enum TraceRequest {
+    /// Requests that tracing begins. Following this being sent, the child must
+    /// wait to receive a `Confirmation` on the respective channel and then
+    /// `raise(SIGSTOP)`.
+    ///
+    /// To avoid possible issues while allocating memory for IPC channels, ending
+    /// the tracing is instead done via `raise(SIGUSR1)`.
+    StartFfi(StartFfiInfo),
+    /// Manually overrides the code that the supervisor will return upon exiting.
+    /// Once set, it is permanent. This can be called again to change the value.
+    OverrideRetcode(i32),
+}
+
+/// Information needed to begin tracing.
+#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
+pub struct StartFfiInfo {
+    /// A vector of page addresses. These should have been automatically obtained
+    /// with `IsolatedAlloc::pages` and prepared with `IsolatedAlloc::prepare_ffi`.
+    pub page_ptrs: Vec<usize>,
+    /// The address of an allocation that can serve as a temporary stack.
+    /// This should be a leaked `Box<[u8; CALLBACK_STACK_SIZE]>` cast to an int.
+    pub stack_ptr: usize,
+}
+
+/// A marker type confirming that the supervisor has received the request to begin
+/// tracing and is now waiting for a `SIGSTOP`.
+///
+/// The sender for this channel should live on the parent process.
+#[derive(serde::Serialize, serde::Deserialize, Debug)]
+pub struct Confirmation;
+
+/// The final results of an FFI trace, containing every relevant event detected
+/// by the tracer. Sent by the supervisor after receiving a `SIGUSR1` signal.
+///
+/// The sender for this channel should live on the parent process.
+#[derive(serde::Serialize, serde::Deserialize, Debug)]
+pub struct MemEvents {
+    /// An ordered list of memory accesses that occurred. These should be assumed
+    /// to be overcautious; that is, if the size of an access is uncertain it is
+    /// pessimistically rounded up, and if the type (read/write/both) is uncertain
+    /// it is reported as whatever would be safest to assume; i.e. a read + maybe-write
+    /// becomes a read + write, etc.
+    pub acc_events: Vec<AccessEvent>,
+}
+
+/// A single memory access, conservatively overestimated
+/// in case of ambiguity.
+#[derive(serde::Serialize, serde::Deserialize, Debug)]
+pub enum AccessEvent {
+    /// A read may have occurred on no more than the specified address range.
+    Read(Range<usize>),
+    /// A write may have occurred on no more than the specified address range.
+    Write(Range<usize>),
+}
diff --git a/src/tools/miri/src/shims/native_lib/trace/mod.rs b/src/tools/miri/src/shims/native_lib/trace/mod.rs
new file mode 100644
index 00000000000..174b06b3ac5
--- /dev/null
+++ b/src/tools/miri/src/shims/native_lib/trace/mod.rs
@@ -0,0 +1,8 @@
+mod child;
+pub mod messages;
+mod parent;
+
+pub use self::child::{Supervisor, init_sv, register_retcode_sv};
+
+/// The size of the temporary stack we use for callbacks that the server executes in the client.
+const CALLBACK_STACK_SIZE: usize = 1024;
diff --git a/src/tools/miri/src/shims/native_lib/trace/parent.rs b/src/tools/miri/src/shims/native_lib/trace/parent.rs
new file mode 100644
index 00000000000..dfb0b35da69
--- /dev/null
+++ b/src/tools/miri/src/shims/native_lib/trace/parent.rs
@@ -0,0 +1,660 @@
+use std::sync::atomic::{AtomicPtr, AtomicUsize};
+
+use ipc_channel::ipc;
+use nix::sys::{ptrace, signal, wait};
+use nix::unistd;
+
+use super::CALLBACK_STACK_SIZE;
+use super::messages::{AccessEvent, Confirmation, MemEvents, StartFfiInfo, TraceRequest};
+
+/// The flags to use when calling `waitid()`.
+/// Since bitwise or on the nix version of these flags is implemented as a trait,
+/// this cannot be const directly so we do it this way.
+const WAIT_FLAGS: wait::WaitPidFlag =
+    wait::WaitPidFlag::from_bits_truncate(libc::WUNTRACED | libc::WEXITED);
+
+/// Arch-specific maximum size a single access might perform. x86 value is set
+/// assuming nothing bigger than AVX-512 is available.
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+const ARCH_MAX_ACCESS_SIZE: usize = 64;
+/// The largest arm64 simd instruction operates on 16 bytes.
+#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
+const ARCH_MAX_ACCESS_SIZE: usize = 16;
+
+/// The default word size on a given platform, in bytes.
+#[cfg(any(target_arch = "x86", target_arch = "arm"))]
+const ARCH_WORD_SIZE: usize = 4;
+#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
+const ARCH_WORD_SIZE: usize = 8;
+
+/// The address of the page set to be edited, initialised to a sentinel null
+/// pointer.
+static PAGE_ADDR: AtomicPtr<u8> = AtomicPtr::new(std::ptr::null_mut());
+/// The host pagesize, initialised to a sentinel zero value.
+pub static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0);
+/// How many consecutive pages to unprotect. 1 by default, unlikely to be set
+/// higher than 2.
+static PAGE_COUNT: AtomicUsize = AtomicUsize::new(1);
+
+/// Allows us to get common arguments from the `user_regs_t` across architectures.
+/// Normally this would land us ABI hell, but thankfully all of our usecases
+/// consist of functions with a small number of register-sized integer arguments.
+/// See <https://man7.org/linux/man-pages/man2/syscall.2.html> for sources.
+trait ArchIndependentRegs {
+    /// Gets the address of the instruction pointer.
+    fn ip(&self) -> usize;
+    /// Set the instruction pointer; remember to also set the stack pointer, or
+    /// else the stack might get messed up!
+    fn set_ip(&mut self, ip: usize);
+    /// Set the stack pointer, ideally to a zeroed-out area.
+    fn set_sp(&mut self, sp: usize);
+}
+
+// It's fine / desirable behaviour for values to wrap here, we care about just
+// preserving the bit pattern.
+#[cfg(target_arch = "x86_64")]
+#[expect(clippy::as_conversions)]
+#[rustfmt::skip]
+impl ArchIndependentRegs for libc::user_regs_struct {
+    #[inline]
+    fn ip(&self) -> usize { self.rip as _ }
+    #[inline]
+    fn set_ip(&mut self, ip: usize) { self.rip = ip as _ }
+    #[inline]
+    fn set_sp(&mut self, sp: usize) { self.rsp = sp as _ }
+}
+
+#[cfg(target_arch = "x86")]
+#[expect(clippy::as_conversions)]
+#[rustfmt::skip]
+impl ArchIndependentRegs for libc::user_regs_struct {
+    #[inline]
+    fn ip(&self) -> usize { self.eip as _ }
+    #[inline]
+    fn set_ip(&mut self, ip: usize) { self.eip = ip as _ }
+    #[inline]
+    fn set_sp(&mut self, sp: usize) { self.esp = sp as _ }
+}
+
+#[cfg(target_arch = "aarch64")]
+#[expect(clippy::as_conversions)]
+#[rustfmt::skip]
+impl ArchIndependentRegs for libc::user_regs_struct {
+    #[inline]
+    fn ip(&self) -> usize { self.pc as _ }
+    #[inline]
+    fn set_ip(&mut self, ip: usize) { self.pc = ip as _ }
+    #[inline]
+    fn set_sp(&mut self, sp: usize) { self.sp = sp as _ }
+}
+
+/// A unified event representing something happening on the child process. Wraps
+/// `nix`'s `WaitStatus` and our custom signals so it can all be done with one
+/// `match` statement.
+pub enum ExecEvent {
+    /// Child process requests that we begin monitoring it.
+    Start(StartFfiInfo),
+    /// Child requests that we stop monitoring and pass over the events we
+    /// detected.
+    End,
+    /// The child process with the specified pid was stopped by the given signal.
+    Status(unistd::Pid, signal::Signal),
+    /// The child process with the specified pid entered or existed a syscall.
+    Syscall(unistd::Pid),
+    /// A child process exited or was killed; if we have a return code, it is
+    /// specified.
+    Died(Option<i32>),
+}
+
+/// A listener for the FFI start info channel along with relevant state.
+pub struct ChildListener {
+    /// The matching channel for the child's `Supervisor` struct.
+    pub message_rx: ipc::IpcReceiver<TraceRequest>,
+    /// Whether an FFI call is currently ongoing.
+    pub attached: bool,
+    /// If `Some`, overrides the return code with the given value.
+    pub override_retcode: Option<i32>,
+}
+
+impl Iterator for ChildListener {
+    type Item = ExecEvent;
+
+    // Allows us to monitor the child process by just iterating over the listener.
+    // NB: This should never return None!
+    fn next(&mut self) -> Option<Self::Item> {
+        // Do not block if the child has nothing to report for `waitid`.
+        let opts = WAIT_FLAGS | wait::WaitPidFlag::WNOHANG;
+        loop {
+            // Listen to any child, not just the main one. Important if we want
+            // to allow the C code to fork further, along with being a bit of
+            // defensive programming since Linux sometimes assigns threads of
+            // the same process different PIDs with unpredictable rules...
+            match wait::waitid(wait::Id::All, opts) {
+                Ok(stat) =>
+                    match stat {
+                        // Child exited normally with a specific code set.
+                        wait::WaitStatus::Exited(_, code) => {
+                            let code = self.override_retcode.unwrap_or(code);
+                            return Some(ExecEvent::Died(Some(code)));
+                        }
+                        // Child was killed by a signal, without giving a code.
+                        wait::WaitStatus::Signaled(_, _, _) =>
+                            return Some(ExecEvent::Died(self.override_retcode)),
+                        // Child entered a syscall. Since we're always technically
+                        // tracing, only pass this along if we're actively
+                        // monitoring the child.
+                        wait::WaitStatus::PtraceSyscall(pid) =>
+                            if self.attached {
+                                return Some(ExecEvent::Syscall(pid));
+                            },
+                        // Child with the given pid was stopped by the given signal.
+                        // It's somewhat dubious when this is returned instead of
+                        // WaitStatus::Stopped, but for our purposes they are the
+                        // same thing.
+                        wait::WaitStatus::PtraceEvent(pid, signal, _) =>
+                            if self.attached {
+                                // This is our end-of-FFI signal!
+                                if signal == signal::SIGUSR1 {
+                                    self.attached = false;
+                                    return Some(ExecEvent::End);
+                                } else {
+                                    return Some(ExecEvent::Status(pid, signal));
+                                }
+                            } else {
+                                // Just pass along the signal.
+                                ptrace::cont(pid, signal).unwrap();
+                            },
+                        // Child was stopped at the given signal. Same logic as for
+                        // WaitStatus::PtraceEvent.
+                        wait::WaitStatus::Stopped(pid, signal) =>
+                            if self.attached {
+                                if signal == signal::SIGUSR1 {
+                                    self.attached = false;
+                                    return Some(ExecEvent::End);
+                                } else {
+                                    return Some(ExecEvent::Status(pid, signal));
+                                }
+                            } else {
+                                ptrace::cont(pid, signal).unwrap();
+                            },
+                        _ => (),
+                    },
+                // This case should only trigger if all children died and we
+                // somehow missed that, but it's best we not allow any room
+                // for deadlocks.
+                Err(_) => return Some(ExecEvent::Died(None)),
+            }
+
+            // Similarly, do a non-blocking poll of the IPC channel.
+            if let Ok(req) = self.message_rx.try_recv() {
+                match req {
+                    TraceRequest::StartFfi(info) =>
+                    // Should never trigger - but better to panic explicitly than deadlock!
+                        if self.attached {
+                            panic!("Attempting to begin FFI multiple times!");
+                        } else {
+                            self.attached = true;
+                            return Some(ExecEvent::Start(info));
+                        },
+                    TraceRequest::OverrideRetcode(code) => self.override_retcode = Some(code),
+                }
+            }
+
+            // Not ideal, but doing anything else might sacrifice performance.
+            std::thread::yield_now();
+        }
+    }
+}
+
+/// An error came up while waiting on the child process to do something.
+/// It likely died, with this return code if we have one.
+#[derive(Debug)]
+pub struct ExecEnd(pub Option<i32>);
+
+/// This is the main loop of the supervisor process. It runs in a separate
+/// process from the rest of Miri (but because we fork, addresses for anything
+/// created before the fork - like statics - are the same).
+pub fn sv_loop(
+    listener: ChildListener,
+    init_pid: unistd::Pid,
+    event_tx: ipc::IpcSender<MemEvents>,
+    confirm_tx: ipc::IpcSender<Confirmation>,
+) -> Result<!, ExecEnd> {
+    // Get the pagesize set and make sure it isn't still on the zero sentinel value!
+    let page_size = PAGE_SIZE.load(std::sync::atomic::Ordering::Relaxed);
+    assert_ne!(page_size, 0);
+
+    // Things that we return to the child process.
+    let mut acc_events = Vec::new();
+
+    // Memory allocated for the MiriMachine.
+    let mut ch_pages = Vec::new();
+    let mut ch_stack = None;
+
+    // An instance of the Capstone disassembler, so we don't spawn one on every access.
+    let cs = get_disasm();
+
+    // The pid of the last process we interacted with, used by default if we don't have a
+    // reason to use a different one.
+    let mut curr_pid = init_pid;
+
+    // There's an initial sigstop we need to deal with.
+    wait_for_signal(Some(curr_pid), signal::SIGSTOP, false)?;
+    ptrace::cont(curr_pid, None).unwrap();
+
+    for evt in listener {
+        match evt {
+            // start_ffi was called by the child, so prep memory.
+            ExecEvent::Start(ch_info) => {
+                // All the pages that the child process is "allowed to" access.
+                ch_pages = ch_info.page_ptrs;
+                // And the temporary callback stack it allocated for us to use later.
+                ch_stack = Some(ch_info.stack_ptr);
+
+                // We received the signal and are no longer in the main listener loop,
+                // so we can let the child move on to the end of start_ffi where it will
+                // raise a SIGSTOP. We need it to be signal-stopped *and waited for* in
+                // order to do most ptrace operations!
+                confirm_tx.send(Confirmation).unwrap();
+                // We can't trust simply calling `Pid::this()` in the child process to give the right
+                // PID for us, so we get it this way.
+                curr_pid = wait_for_signal(None, signal::SIGSTOP, false).unwrap();
+
+                ptrace::syscall(curr_pid, None).unwrap();
+            }
+            // end_ffi was called by the child.
+            ExecEvent::End => {
+                // Hand over the access info we traced.
+                event_tx.send(MemEvents { acc_events }).unwrap();
+                // And reset our values.
+                acc_events = Vec::new();
+                ch_stack = None;
+
+                // No need to monitor syscalls anymore, they'd just be ignored.
+                ptrace::cont(curr_pid, None).unwrap();
+            }
+            // Child process was stopped by a signal
+            ExecEvent::Status(pid, signal) =>
+                match signal {
+                    // If it was a segfault, check if it was an artificial one
+                    // caused by it trying to access the MiriMachine memory.
+                    signal::SIGSEGV =>
+                        handle_segfault(
+                            pid,
+                            &ch_pages,
+                            ch_stack.unwrap(),
+                            page_size,
+                            &cs,
+                            &mut acc_events,
+                        )?,
+                    // Something weird happened.
+                    _ => {
+                        eprintln!("Process unexpectedly got {signal}; continuing...");
+                        // In case we're not tracing
+                        if ptrace::syscall(pid, None).is_err() {
+                            // If *this* fails too, something really weird happened
+                            // and it's probably best to just panic.
+                            signal::kill(pid, signal::SIGCONT).unwrap();
+                        }
+                    }
+                },
+            // Child entered a syscall; we wait for exits inside of this, so it
+            // should never trigger on return from a syscall we care about.
+            ExecEvent::Syscall(pid) => {
+                ptrace::syscall(pid, None).unwrap();
+            }
+            ExecEvent::Died(code) => {
+                return Err(ExecEnd(code));
+            }
+        }
+    }
+
+    unreachable!()
+}
+
+/// Spawns a Capstone disassembler for the host architecture.
+#[rustfmt::skip]
+fn get_disasm() -> capstone::Capstone {
+    use capstone::prelude::*;
+    let cs_pre = Capstone::new();
+    {
+        #[cfg(target_arch = "x86_64")]
+        {cs_pre.x86().mode(arch::x86::ArchMode::Mode64)}
+        #[cfg(target_arch = "x86")]
+        {cs_pre.x86().mode(arch::x86::ArchMode::Mode32)}
+        #[cfg(target_arch = "aarch64")]
+        {cs_pre.arm64().mode(arch::arm64::ArchMode::Arm)}
+        #[cfg(target_arch = "arm")]
+        {cs_pre.arm().mode(arch::arm::ArchMode::Arm)}
+    }
+    .detail(true)
+    .build()
+    .unwrap()
+}
+
+/// Waits for `wait_signal`. If `init_cont`, it will first do a `ptrace::cont`.
+/// We want to avoid that in some cases, like at the beginning of FFI.
+///
+/// If `pid` is `None`, only one wait will be done and `init_cont` should be false.
+fn wait_for_signal(
+    pid: Option<unistd::Pid>,
+    wait_signal: signal::Signal,
+    init_cont: bool,
+) -> Result<unistd::Pid, ExecEnd> {
+    if init_cont {
+        ptrace::cont(pid.unwrap(), None).unwrap();
+    }
+    // Repeatedly call `waitid` until we get the signal we want, or the process dies.
+    loop {
+        let wait_id = match pid {
+            Some(pid) => wait::Id::Pid(pid),
+            None => wait::Id::All,
+        };
+        let stat = wait::waitid(wait_id, WAIT_FLAGS).map_err(|_| ExecEnd(None))?;
+        let (signal, pid) = match stat {
+            // Report the cause of death, if we know it.
+            wait::WaitStatus::Exited(_, code) => {
+                return Err(ExecEnd(Some(code)));
+            }
+            wait::WaitStatus::Signaled(_, _, _) => return Err(ExecEnd(None)),
+            wait::WaitStatus::Stopped(pid, signal) => (signal, pid),
+            wait::WaitStatus::PtraceEvent(pid, signal, _) => (signal, pid),
+            // This covers PtraceSyscall and variants that are impossible with
+            // the flags set (e.g. WaitStatus::StillAlive).
+            _ => {
+                ptrace::cont(pid.unwrap(), None).unwrap();
+                continue;
+            }
+        };
+        if signal == wait_signal {
+            return Ok(pid);
+        } else {
+            ptrace::cont(pid, signal).map_err(|_| ExecEnd(None))?;
+        }
+    }
+}
+
+/// Grabs the access that caused a segfault and logs it down if it's to our memory,
+/// or kills the child and returns the appropriate error otherwise.
+fn handle_segfault(
+    pid: unistd::Pid,
+    ch_pages: &[usize],
+    ch_stack: usize,
+    page_size: usize,
+    cs: &capstone::Capstone,
+    acc_events: &mut Vec<AccessEvent>,
+) -> Result<(), ExecEnd> {
+    /// This is just here to not pollute the main namespace with `capstone::prelude::*`.
+    #[inline]
+    fn capstone_disassemble(
+        instr: &[u8],
+        addr: usize,
+        cs: &capstone::Capstone,
+        acc_events: &mut Vec<AccessEvent>,
+    ) -> capstone::CsResult<()> {
+        use capstone::prelude::*;
+
+        // The arch_detail is what we care about, but it relies on these temporaries
+        // that we can't drop. 0x1000 is the default base address for Captsone, and
+        // we're expecting 1 instruction.
+        let insns = cs.disasm_count(instr, 0x1000, 1)?;
+        let ins_detail = cs.insn_detail(&insns[0])?;
+        let arch_detail = ins_detail.arch_detail();
+
+        for op in arch_detail.operands() {
+            match op {
+                #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+                arch::ArchOperand::X86Operand(x86_operand) => {
+                    match x86_operand.op_type {
+                        // We only care about memory accesses
+                        arch::x86::X86OperandType::Mem(_) => {
+                            let push = addr..addr.strict_add(usize::from(x86_operand.size));
+                            // It's called a "RegAccessType" but it also applies to memory
+                            let acc_ty = x86_operand.access.unwrap();
+                            if acc_ty.is_readable() {
+                                acc_events.push(AccessEvent::Read(push.clone()));
+                            }
+                            if acc_ty.is_writable() {
+                                acc_events.push(AccessEvent::Write(push));
+                            }
+                        }
+                        _ => (),
+                    }
+                }
+                #[cfg(target_arch = "aarch64")]
+                arch::ArchOperand::Arm64Operand(arm64_operand) => {
+                    // Annoyingly, we don't always get the size here, so just be pessimistic for now.
+                    match arm64_operand.op_type {
+                        arch::arm64::Arm64OperandType::Mem(_) => {
+                            // B = 1 byte, H = 2 bytes, S = 4 bytes, D = 8 bytes, Q = 16 bytes.
+                            let size = match arm64_operand.vas {
+                                // Not an fp/simd instruction.
+                                arch::arm64::Arm64Vas::ARM64_VAS_INVALID => ARCH_WORD_SIZE,
+                                // 1 byte.
+                                arch::arm64::Arm64Vas::ARM64_VAS_1B => 1,
+                                // 2 bytes.
+                                arch::arm64::Arm64Vas::ARM64_VAS_1H => 2,
+                                // 4 bytes.
+                                arch::arm64::Arm64Vas::ARM64_VAS_4B
+                                | arch::arm64::Arm64Vas::ARM64_VAS_2H
+                                | arch::arm64::Arm64Vas::ARM64_VAS_1S => 4,
+                                // 8 bytes.
+                                arch::arm64::Arm64Vas::ARM64_VAS_8B
+                                | arch::arm64::Arm64Vas::ARM64_VAS_4H
+                                | arch::arm64::Arm64Vas::ARM64_VAS_2S
+                                | arch::arm64::Arm64Vas::ARM64_VAS_1D => 8,
+                                // 16 bytes.
+                                arch::arm64::Arm64Vas::ARM64_VAS_16B
+                                | arch::arm64::Arm64Vas::ARM64_VAS_8H
+                                | arch::arm64::Arm64Vas::ARM64_VAS_4S
+                                | arch::arm64::Arm64Vas::ARM64_VAS_2D
+                                | arch::arm64::Arm64Vas::ARM64_VAS_1Q => 16,
+                            };
+                            let push = addr..addr.strict_add(size);
+                            // FIXME: This now has access type info in the latest
+                            // git version of capstone because this pissed me off
+                            // and I added it. Change this when it updates.
+                            acc_events.push(AccessEvent::Read(push.clone()));
+                            acc_events.push(AccessEvent::Write(push));
+                        }
+                        _ => (),
+                    }
+                }
+                #[cfg(target_arch = "arm")]
+                arch::ArchOperand::ArmOperand(arm_operand) =>
+                    match arm_operand.op_type {
+                        arch::arm::ArmOperandType::Mem(_) => {
+                            // We don't get info on the size of the access, but
+                            // we're at least told if it's a vector instruction.
+                            let size = if arm_operand.vector_index.is_some() {
+                                ARCH_MAX_ACCESS_SIZE
+                            } else {
+                                ARCH_WORD_SIZE
+                            };
+                            let push = addr..addr.strict_add(size);
+                            let acc_ty = arm_operand.access.unwrap();
+                            if acc_ty.is_readable() {
+                                acc_events.push(AccessEvent::Read(push.clone()));
+                            }
+                            if acc_ty.is_writable() {
+                                acc_events.push(AccessEvent::Write(push));
+                            }
+                        }
+                        _ => (),
+                    },
+                _ => unimplemented!(),
+            }
+        }
+
+        Ok(())
+    }
+
+    // Get information on what caused the segfault. This contains the address
+    // that triggered it.
+    let siginfo = ptrace::getsiginfo(pid).unwrap();
+    // All x86, ARM, etc. instructions only have at most one memory operand
+    // (thankfully!)
+    // SAFETY: si_addr is safe to call.
+    let addr = unsafe { siginfo.si_addr().addr() };
+    let page_addr = addr.strict_sub(addr.strict_rem(page_size));
+
+    if !ch_pages.iter().any(|pg| (*pg..pg.strict_add(page_size)).contains(&addr)) {
+        // This was a real segfault (not one of the Miri memory pages), so print some debug info and
+        // quit.
+        let regs = ptrace::getregs(pid).unwrap();
+        eprintln!("Segfault occurred during FFI at {addr:#018x}");
+        eprintln!("Expected access on pages: {ch_pages:#018x?}");
+        eprintln!("Register dump: {regs:#x?}");
+        ptrace::kill(pid).unwrap();
+        return Err(ExecEnd(None));
+    }
+
+    // Overall structure:
+    // - Get the address that caused the segfault
+    // - Unprotect the memory: we force the child to execute `mempr_off`, passing parameters via
+    //   global atomic variables. This is what we use the temporary callback stack for.
+    // - Step 1 instruction
+    // - Parse executed code to estimate size & type of access
+    // - Reprotect the memory by executing `mempr_on` in the child.
+    // - Continue
+
+    // Ensure the stack is properly zeroed out!
+    for a in (ch_stack..ch_stack.strict_add(CALLBACK_STACK_SIZE)).step_by(ARCH_WORD_SIZE) {
+        ptrace::write(pid, std::ptr::with_exposed_provenance_mut(a), 0).unwrap();
+    }
+
+    // Guard against both architectures with upwards and downwards-growing stacks.
+    let stack_ptr = ch_stack.strict_add(CALLBACK_STACK_SIZE / 2);
+    let regs_bak = ptrace::getregs(pid).unwrap();
+    let mut new_regs = regs_bak;
+    let ip_prestep = regs_bak.ip();
+
+    // Move the instr ptr into the deprotection code.
+    #[expect(clippy::as_conversions)]
+    new_regs.set_ip(mempr_off as usize);
+    // Don't mess up the stack by accident!
+    new_regs.set_sp(stack_ptr);
+
+    // Modify the PAGE_ADDR global on the child process to point to the page
+    // that we want unprotected.
+    ptrace::write(
+        pid,
+        (&raw const PAGE_ADDR).cast_mut().cast(),
+        libc::c_long::try_from(page_addr).unwrap(),
+    )
+    .unwrap();
+
+    // Check if we also own the next page, and if so unprotect it in case
+    // the access spans the page boundary.
+    let flag = if ch_pages.contains(&page_addr.strict_add(page_size)) { 2 } else { 1 };
+    ptrace::write(pid, (&raw const PAGE_COUNT).cast_mut().cast(), flag).unwrap();
+
+    ptrace::setregs(pid, new_regs).unwrap();
+
+    // Our mempr_* functions end with a raise(SIGSTOP).
+    wait_for_signal(Some(pid), signal::SIGSTOP, true)?;
+
+    // Step 1 instruction.
+    ptrace::setregs(pid, regs_bak).unwrap();
+    ptrace::step(pid, None).unwrap();
+    // Don't use wait_for_signal here since 1 instruction doesn't give room
+    // for any uncertainty + we don't want it `cont()`ing randomly by accident
+    // Also, don't let it continue with unprotected memory if something errors!
+    let _ = wait::waitid(wait::Id::Pid(pid), WAIT_FLAGS).map_err(|_| ExecEnd(None))?;
+
+    // Zero out again to be safe
+    for a in (ch_stack..ch_stack.strict_add(CALLBACK_STACK_SIZE)).step_by(ARCH_WORD_SIZE) {
+        ptrace::write(pid, std::ptr::with_exposed_provenance_mut(a), 0).unwrap();
+    }
+
+    // Save registers and grab the bytes that were executed. This would
+    // be really nasty if it was a jump or similar but those thankfully
+    // won't do memory accesses and so can't trigger this!
+    let regs_bak = ptrace::getregs(pid).unwrap();
+    new_regs = regs_bak;
+    let ip_poststep = regs_bak.ip();
+    // We need to do reads/writes in word-sized chunks.
+    let diff = (ip_poststep.strict_sub(ip_prestep)).div_ceil(ARCH_WORD_SIZE);
+    let instr = (ip_prestep..ip_prestep.strict_add(diff)).fold(vec![], |mut ret, ip| {
+        // This only needs to be a valid pointer in the child process, not ours.
+        ret.append(
+            &mut ptrace::read(pid, std::ptr::without_provenance_mut(ip))
+                .unwrap()
+                .to_ne_bytes()
+                .to_vec(),
+        );
+        ret
+    });
+
+    // Now figure out the size + type of access and log it down.
+    // This will mark down e.g. the same area being read multiple times,
+    // since it's more efficient to compress the accesses at the end.
+    if capstone_disassemble(&instr, addr, cs, acc_events).is_err() {
+        // Read goes first because we need to be pessimistic.
+        acc_events.push(AccessEvent::Read(addr..addr.strict_add(ARCH_MAX_ACCESS_SIZE)));
+        acc_events.push(AccessEvent::Write(addr..addr.strict_add(ARCH_MAX_ACCESS_SIZE)));
+    }
+
+    // Reprotect everything and continue.
+    #[expect(clippy::as_conversions)]
+    new_regs.set_ip(mempr_on as usize);
+    new_regs.set_sp(stack_ptr);
+    ptrace::setregs(pid, new_regs).unwrap();
+    wait_for_signal(Some(pid), signal::SIGSTOP, true)?;
+
+    ptrace::setregs(pid, regs_bak).unwrap();
+    ptrace::syscall(pid, None).unwrap();
+    Ok(())
+}
+
+// We only get dropped into these functions via offsetting the instr pointer
+// manually, so we *must not ever* unwind from them.
+
+/// Disables protections on the page whose address is currently in `PAGE_ADDR`.
+///
+/// SAFETY: `PAGE_ADDR` should be set to a page-aligned pointer to an owned page,
+/// `PAGE_SIZE` should be the host pagesize, and the range from `PAGE_ADDR` to
+/// `PAGE_SIZE` * `PAGE_COUNT` must be owned and allocated memory. No other threads
+/// should be running.
+pub unsafe extern "C" fn mempr_off() {
+    use std::sync::atomic::Ordering;
+
+    // Again, cannot allow unwinds to happen here.
+    let len = PAGE_SIZE.load(Ordering::Relaxed).saturating_mul(PAGE_COUNT.load(Ordering::Relaxed));
+    // SAFETY: Upheld by "caller".
+    unsafe {
+        // It's up to the caller to make sure this doesn't actually overflow, but
+        // we mustn't unwind from here, so...
+        if libc::mprotect(
+            PAGE_ADDR.load(Ordering::Relaxed).cast(),
+            len,
+            libc::PROT_READ | libc::PROT_WRITE,
+        ) != 0
+        {
+            // Can't return or unwind, but we can do this.
+            std::process::exit(-1);
+        }
+    }
+    // If this fails somehow we're doomed.
+    if signal::raise(signal::SIGSTOP).is_err() {
+        std::process::exit(-1);
+    }
+}
+
+/// Reenables protection on the page set by `PAGE_ADDR`.
+///
+/// SAFETY: See `mempr_off()`.
+pub unsafe extern "C" fn mempr_on() {
+    use std::sync::atomic::Ordering;
+
+    let len = PAGE_SIZE.load(Ordering::Relaxed).wrapping_mul(PAGE_COUNT.load(Ordering::Relaxed));
+    // SAFETY: Upheld by "caller".
+    unsafe {
+        if libc::mprotect(PAGE_ADDR.load(Ordering::Relaxed).cast(), len, libc::PROT_NONE) != 0 {
+            std::process::exit(-1);
+        }
+    }
+    if signal::raise(signal::SIGSTOP).is_err() {
+        std::process::exit(-1);
+    }
+}
diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs
index a6bce830149..9490761d0c9 100644
--- a/src/tools/miri/src/shims/panic.rs
+++ b/src/tools/miri/src/shims/panic.rs
@@ -92,7 +92,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             &[data.clone()],
             None,
             // Directly return to caller.
-            StackPopCleanup::Goto { ret, unwind: mir::UnwindAction::Continue },
+            ReturnContinuation::Goto { ret, unwind: mir::UnwindAction::Continue },
         )?;
 
         // We ourselves will return `0`, eventually (will be overwritten if we catch a panic).
@@ -143,7 +143,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 &[catch_unwind.data, payload],
                 None,
                 // Directly return to caller of `catch_unwind`.
-                StackPopCleanup::Goto {
+                ReturnContinuation::Goto {
                     ret: catch_unwind.ret,
                     // `catch_fn` must not unwind.
                     unwind: mir::UnwindAction::Unreachable,
@@ -172,7 +172,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             ExternAbi::Rust,
             &[this.mplace_to_ref(&msg)?],
             None,
-            StackPopCleanup::Goto { ret: None, unwind },
+            ReturnContinuation::Goto { ret: None, unwind },
         )
     }
 
@@ -191,7 +191,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             ExternAbi::Rust,
             &[this.mplace_to_ref(&msg)?],
             None,
-            StackPopCleanup::Goto { ret: None, unwind: mir::UnwindAction::Unreachable },
+            ReturnContinuation::Goto { ret: None, unwind: mir::UnwindAction::Unreachable },
         )
     }
 
@@ -220,7 +220,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     ExternAbi::Rust,
                     &[index, len],
                     None,
-                    StackPopCleanup::Goto { ret: None, unwind },
+                    ReturnContinuation::Goto { ret: None, unwind },
                 )?;
             }
             MisalignedPointerDereference { required, found } => {
@@ -241,7 +241,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     ExternAbi::Rust,
                     &[required, found],
                     None,
-                    StackPopCleanup::Goto { ret: None, unwind },
+                    ReturnContinuation::Goto { ret: None, unwind },
                 )?;
             }
 
@@ -254,7 +254,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     ExternAbi::Rust,
                     &[],
                     None,
-                    StackPopCleanup::Goto { ret: None, unwind },
+                    ReturnContinuation::Goto { ret: None, unwind },
                 )?;
             }
         }
diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs
index 28f4ca5bb1b..eb21abc2a45 100644
--- a/src/tools/miri/src/shims/time.rs
+++ b/src/tools/miri/src/shims/time.rs
@@ -330,18 +330,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         interp_ok(Scalar::from_i32(0)) // KERN_SUCCESS
     }
 
-    fn nanosleep(
-        &mut self,
-        req_op: &OpTy<'tcx>,
-        _rem: &OpTy<'tcx>, // Signal handlers are not supported, so rem will never be written to.
-    ) -> InterpResult<'tcx, Scalar> {
+    fn nanosleep(&mut self, duration: &OpTy<'tcx>, rem: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         this.assert_target_os_is_unix("nanosleep");
 
-        let req = this.deref_pointer_as(req_op, this.libc_ty_layout("timespec"))?;
+        let duration = this.deref_pointer_as(duration, this.libc_ty_layout("timespec"))?;
+        let _rem = this.read_pointer(rem)?; // Signal handlers are not supported, so rem will never be written to.
 
-        let duration = match this.read_timespec(&req)? {
+        let duration = match this.read_timespec(&duration)? {
             Some(duration) => duration,
             None => {
                 return this.set_last_error_and_return_i32(LibcError("EINVAL"));
@@ -362,6 +359,63 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         interp_ok(Scalar::from_i32(0))
     }
 
+    fn clock_nanosleep(
+        &mut self,
+        clock_id: &OpTy<'tcx>,
+        flags: &OpTy<'tcx>,
+        timespec: &OpTy<'tcx>,
+        rem: &OpTy<'tcx>,
+    ) -> InterpResult<'tcx, Scalar> {
+        let this = self.eval_context_mut();
+        let clockid_t_size = this.libc_ty_layout("clockid_t").size;
+
+        let clock_id = this.read_scalar(clock_id)?.to_int(clockid_t_size)?;
+        let timespec = this.deref_pointer_as(timespec, this.libc_ty_layout("timespec"))?;
+        let flags = this.read_scalar(flags)?.to_i32()?;
+        let _rem = this.read_pointer(rem)?; // Signal handlers are not supported, so rem will never be written to.
+
+        // The standard lib through sleep_until only needs CLOCK_MONOTONIC
+        if clock_id != this.eval_libc("CLOCK_MONOTONIC").to_int(clockid_t_size)? {
+            throw_unsup_format!("clock_nanosleep: only CLOCK_MONOTONIC is supported");
+        }
+
+        let duration = match this.read_timespec(&timespec)? {
+            Some(duration) => duration,
+            None => {
+                return this.set_last_error_and_return_i32(LibcError("EINVAL"));
+            }
+        };
+
+        let timeout_anchor = if flags == 0 {
+            // No flags set, the timespec should be interperted as a duration
+            // to sleep for
+            TimeoutAnchor::Relative
+        } else if flags == this.eval_libc_i32("TIMER_ABSTIME") {
+            // Only flag TIMER_ABSTIME set, the timespec should be interperted as
+            // an absolute time.
+            TimeoutAnchor::Absolute
+        } else {
+            // The standard lib (through `sleep_until`) only needs TIMER_ABSTIME
+            throw_unsup_format!(
+                "`clock_nanosleep` unsupported flags {flags}, only no flags or \
+                TIMER_ABSTIME is supported"
+            );
+        };
+
+        this.block_thread(
+            BlockReason::Sleep,
+            Some((TimeoutClock::Monotonic, timeout_anchor, duration)),
+            callback!(
+                @capture<'tcx> {}
+                |_this, unblock: UnblockKind| {
+                    assert_eq!(unblock, UnblockKind::TimedOut);
+                    interp_ok(())
+                }
+            ),
+        );
+        interp_ok(Scalar::from_i32(0))
+    }
+
     #[allow(non_snake_case)]
     fn Sleep(&mut self, timeout: &OpTy<'tcx>) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
diff --git a/src/tools/miri/src/shims/tls.rs b/src/tools/miri/src/shims/tls.rs
index 46a417689a2..7182637437a 100644
--- a/src/tools/miri/src/shims/tls.rs
+++ b/src/tools/miri/src/shims/tls.rs
@@ -325,7 +325,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             ExternAbi::System { unwind: false },
             &[null_ptr.clone(), ImmTy::from_scalar(reason, this.machine.layouts.u32), null_ptr],
             None,
-            StackPopCleanup::Root { cleanup: true },
+            ReturnContinuation::Stop { cleanup: true },
         )?;
         interp_ok(())
     }
@@ -346,7 +346,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 ExternAbi::C { unwind: false },
                 &[ImmTy::from_scalar(data, this.machine.layouts.mut_raw_ptr)],
                 None,
-                StackPopCleanup::Root { cleanup: true },
+                ReturnContinuation::Stop { cleanup: true },
             )?;
 
             return interp_ok(Poll::Pending);
@@ -383,7 +383,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 ExternAbi::C { unwind: false },
                 &[ImmTy::from_scalar(ptr, this.machine.layouts.mut_raw_ptr)],
                 None,
-                StackPopCleanup::Root { cleanup: true },
+                ReturnContinuation::Stop { cleanup: true },
             )?;
 
             return interp_ok(Poll::Pending);
diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs
index 604fb0974d2..eb4365e2004 100644
--- a/src/tools/miri/src/shims/unix/env.rs
+++ b/src/tools/miri/src/shims/unix/env.rs
@@ -1,6 +1,6 @@
+use std::env;
 use std::ffi::{OsStr, OsString};
 use std::io::ErrorKind;
-use std::{env, mem};
 
 use rustc_abi::{FieldIdx, Size};
 use rustc_data_structures::fx::FxHashMap;
@@ -50,20 +50,6 @@ impl<'tcx> UnixEnvVars<'tcx> {
         interp_ok(UnixEnvVars { map: env_vars_machine, environ })
     }
 
-    pub(crate) fn cleanup(ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>) -> InterpResult<'tcx> {
-        // Deallocate individual env vars.
-        let env_vars = mem::take(&mut ecx.machine.env_vars.unix_mut().map);
-        for (_name, ptr) in env_vars {
-            ecx.deallocate_ptr(ptr, None, MiriMemoryKind::Runtime.into())?;
-        }
-        // Deallocate environ var list.
-        let environ = &ecx.machine.env_vars.unix().environ;
-        let old_vars_ptr = ecx.read_pointer(environ)?;
-        ecx.deallocate_ptr(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?;
-
-        interp_ok(())
-    }
-
     pub(crate) fn environ(&self) -> Pointer {
         self.environ.ptr()
     }
@@ -112,7 +98,7 @@ fn alloc_env_var<'tcx>(
     let mut name_osstring = name.to_os_string();
     name_osstring.push("=");
     name_osstring.push(value);
-    ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Runtime.into())
+    ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())
 }
 
 /// Allocates an `environ` block with the given list of pointers.
@@ -128,7 +114,7 @@ fn alloc_environ_block<'tcx>(
         ecx.machine.layouts.mut_raw_ptr.ty,
         u64::try_from(vars.len()).unwrap(),
     ))?;
-    let vars_place = ecx.allocate(vars_layout, MiriMemoryKind::Runtime.into())?;
+    let vars_place = ecx.allocate(vars_layout, MiriMemoryKind::Machine.into())?;
     for (idx, var) in vars.into_iter_enumerated() {
         let place = ecx.project_field(&vars_place, idx)?;
         ecx.write_pointer(var, &place)?;
@@ -171,7 +157,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let Some((name, value)) = new {
             let var_ptr = alloc_env_var(this, &name, &value)?;
             if let Some(var) = this.machine.env_vars.unix_mut().map.insert(name, var_ptr) {
-                this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?;
+                this.deallocate_ptr(var, None, MiriMemoryKind::Machine.into())?;
             }
             this.update_environ()?;
             interp_ok(Scalar::from_i32(0)) // return zero on success
@@ -195,7 +181,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         }
         if let Some(old) = success {
             if let Some(var) = old {
-                this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?;
+                this.deallocate_ptr(var, None, MiriMemoryKind::Machine.into())?;
             }
             this.update_environ()?;
             interp_ok(Scalar::from_i32(0))
@@ -253,7 +239,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Deallocate the old environ list.
         let environ = this.machine.env_vars.unix().environ.clone();
         let old_vars_ptr = this.read_pointer(&environ)?;
-        this.deallocate_ptr(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?;
+        this.deallocate_ptr(old_vars_ptr, None, MiriMemoryKind::Machine.into())?;
 
         // Write the new list.
         let vals = this.machine.env_vars.unix().map.values().copied().collect();
@@ -274,15 +260,52 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         interp_ok(Scalar::from_u32(this.get_pid()))
     }
 
-    fn linux_gettid(&mut self) -> InterpResult<'tcx, Scalar> {
+    /// The `gettid`-like function for Unix platforms that take no parameters and return a 32-bit
+    /// integer. It is not always named "gettid".
+    fn unix_gettid(&mut self, link_name: &str) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_ref();
-        this.assert_target_os("linux", "gettid");
+        this.assert_target_os_is_unix(link_name);
+
+        // For most platforms the return type is an `i32`, but some are unsigned. The TID
+        // will always be positive so we don't need to differentiate.
+        interp_ok(Scalar::from_u32(this.get_current_tid()))
+    }
 
-        let index = this.machine.threads.active_thread().to_u32();
+    /// The Apple-specific `int pthread_threadid_np(pthread_t thread, uint64_t *thread_id)`, which
+    /// allows querying the ID for arbitrary threads, identified by their pthread_t.
+    ///
+    /// API documentation: <https://www.manpagez.com/man/3/pthread_threadid_np/>.
+    fn apple_pthread_threadip_np(
+        &mut self,
+        thread_op: &OpTy<'tcx>,
+        tid_op: &OpTy<'tcx>,
+    ) -> InterpResult<'tcx, Scalar> {
+        let this = self.eval_context_mut();
+        this.assert_target_os("macos", "pthread_threadip_np");
+
+        let tid_dest = this.read_pointer(tid_op)?;
+        if this.ptr_is_null(tid_dest)? {
+            // If NULL is passed, an error is immediately returned
+            return interp_ok(this.eval_libc("EINVAL"));
+        }
+
+        let thread = this.read_scalar(thread_op)?.to_int(this.libc_ty_layout("pthread_t").size)?;
+        let thread = if thread == 0 {
+            // Null thread ID indicates that we are querying the active thread.
+            this.machine.threads.active_thread()
+        } else {
+            // Our pthread_t is just the raw ThreadId.
+            let Ok(thread) = this.thread_id_try_from(thread) else {
+                return interp_ok(this.eval_libc("ESRCH"));
+            };
+            thread
+        };
 
-        // Compute a TID for this thread, ensuring that the main thread has PID == TID.
-        let tid = this.get_pid().strict_add(index);
+        let tid = this.get_tid(thread);
+        let tid_dest = this.deref_pointer_as(tid_op, this.machine.layouts.u64)?;
+        this.write_int(tid, &tid_dest)?;
 
-        interp_ok(Scalar::from_u32(tid))
+        // Possible errors have been handled, return success.
+        interp_ok(Scalar::from_u32(0))
     }
 }
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index 14ebb22dc2b..548eabb1b9f 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -945,8 +945,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             "pthread_join" => {
                 let [thread, retval] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
-                let res = this.pthread_join(thread, retval)?;
-                this.write_scalar(res, dest)?;
+                this.pthread_join(thread, retval, dest)?;
             }
             "pthread_detach" => {
                 let [thread] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
@@ -964,8 +963,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_null(dest)?;
             }
             "nanosleep" => {
-                let [req, rem] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
-                let result = this.nanosleep(req, rem)?;
+                let [duration, rem] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+                let result = this.nanosleep(duration, rem)?;
+                this.write_scalar(result, dest)?;
+            }
+            "clock_nanosleep" => {
+                // Currently this function does not exist on all Unixes, e.g. on macOS.
+                this.check_target_os(
+                    &["freebsd", "linux", "android", "solaris", "illumos"],
+                    link_name,
+                )?;
+                let [clock_id, flags, req, rem] =
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
+                let result = this.clock_nanosleep(clock_id, flags, req, rem)?;
                 this.write_scalar(result, dest)?;
             }
             "sched_getaffinity" => {
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 42502d5bf09..33564a2f84c 100644
--- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
@@ -56,6 +56,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 };
                 this.write_scalar(res, dest)?;
             }
+            "pthread_getthreadid_np" => {
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+                let result = this.unix_gettid(link_name.as_str())?;
+                this.write_scalar(result, dest)?;
+            }
 
             "cpuset_getaffinity" => {
                 // The "same" kind of api as `sched_getaffinity` but more fine grained control for FreeBSD specifically.
diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
index aeaff1cb13a..b3e99e6cc68 100644
--- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
@@ -18,7 +18,7 @@ use crate::*;
 const TASK_COMM_LEN: u64 = 16;
 
 pub fn is_dyn_sym(name: &str) -> bool {
-    matches!(name, "statx")
+    matches!(name, "gettid" | "statx")
 }
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
@@ -117,7 +117,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             "gettid" => {
                 let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
-                let result = this.linux_gettid()?;
+                let result = this.unix_gettid(link_name.as_str())?;
                 this.write_scalar(result, dest)?;
             }
 
diff --git a/src/tools/miri/src/shims/unix/linux/mem.rs b/src/tools/miri/src/shims/unix/linux/mem.rs
index 8e5a3021b1c..47732f811f1 100644
--- a/src/tools/miri/src/shims/unix/linux/mem.rs
+++ b/src/tools/miri/src/shims/unix/linux/mem.rs
@@ -22,8 +22,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let flags = this.read_scalar(flags)?.to_i32()?;
 
         // old_address must be a multiple of the page size
-        #[expect(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero
-        if old_address.addr().bytes() % this.machine.page_size != 0 || new_size == 0 {
+        if !old_address.addr().bytes().is_multiple_of(this.machine.page_size) || new_size == 0 {
             this.set_last_error(LibcError("EINVAL"))?;
             return interp_ok(this.eval_libc("MAP_FAILED"));
         }
diff --git a/src/tools/miri/src/shims/unix/linux_like/sync.rs b/src/tools/miri/src/shims/unix/linux_like/sync.rs
index 86e8b57824c..9fad74c0241 100644
--- a/src/tools/miri/src/shims/unix/linux_like/sync.rs
+++ b/src/tools/miri/src/shims/unix/linux_like/sync.rs
@@ -15,12 +15,13 @@ pub fn futex<'tcx>(
 ) -> InterpResult<'tcx> {
     let [addr, op, val] = check_min_vararg_count("`syscall(SYS_futex, ...)`", varargs)?;
 
+    // See <https://man7.org/linux/man-pages/man2/futex.2.html> for docs.
     // The first three arguments (after the syscall number itself) are the same to all futex operations:
-    //     (int *addr, int op, int val).
+    //     (uint32_t *addr, int op, uint32_t val).
     // We checked above that these definitely exist.
     let addr = ecx.read_pointer(addr)?;
     let op = ecx.read_scalar(op)?.to_i32()?;
-    let val = ecx.read_scalar(val)?.to_i32()?;
+    let val = ecx.read_scalar(val)?.to_u32()?;
 
     // This is a vararg function so we have to bring our own type for this pointer.
     let addr = ecx.ptr_to_mplace(addr, ecx.machine.layouts.i32);
@@ -138,7 +139,7 @@ pub fn futex<'tcx>(
             // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`.
             // We do an acquire read -- it only seems reasonable that if we observe a value here, we
             // actually establish an ordering with that value.
-            let futex_val = ecx.read_scalar_atomic(&addr, AtomicReadOrd::Acquire)?.to_i32()?;
+            let futex_val = ecx.read_scalar_atomic(&addr, AtomicReadOrd::Acquire)?.to_u32()?;
             if val == futex_val {
                 // The value still matches, so we block the thread and make it wait for FUTEX_WAKE.
 
diff --git a/src/tools/miri/src/shims/unix/linux_like/syscall.rs b/src/tools/miri/src/shims/unix/linux_like/syscall.rs
index d42d6b9073e..d3534e6e1bc 100644
--- a/src/tools/miri/src/shims/unix/linux_like/syscall.rs
+++ b/src/tools/miri/src/shims/unix/linux_like/syscall.rs
@@ -4,6 +4,7 @@ use rustc_span::Symbol;
 use rustc_target::callconv::FnAbi;
 
 use crate::helpers::check_min_vararg_count;
+use crate::shims::unix::env::EvalContextExt;
 use crate::shims::unix::linux_like::eventfd::EvalContextExt as _;
 use crate::shims::unix::linux_like::sync::futex;
 use crate::*;
@@ -24,6 +25,7 @@ pub fn syscall<'tcx>(
     let sys_getrandom = ecx.eval_libc("SYS_getrandom").to_target_usize(ecx)?;
     let sys_futex = ecx.eval_libc("SYS_futex").to_target_usize(ecx)?;
     let sys_eventfd2 = ecx.eval_libc("SYS_eventfd2").to_target_usize(ecx)?;
+    let sys_gettid = ecx.eval_libc("SYS_gettid").to_target_usize(ecx)?;
 
     match ecx.read_target_usize(op)? {
         // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)`
@@ -53,6 +55,10 @@ pub fn syscall<'tcx>(
             let result = ecx.eventfd(initval, flags)?;
             ecx.write_int(result.to_i32()?, dest)?;
         }
+        num if num == sys_gettid => {
+            let result = ecx.unix_gettid("SYS_gettid")?;
+            ecx.write_int(result.to_u32()?, dest)?;
+        }
         num => {
             throw_unsup_format!("syscall: unsupported syscall number {num}");
         }
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 ae921a013a4..23303718091 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -222,6 +222,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 };
                 this.write_scalar(res, dest)?;
             }
+            "pthread_threadid_np" => {
+                let [thread, tid_ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+                let res = this.apple_pthread_threadip_np(thread, tid_ptr)?;
+                this.write_scalar(res, dest)?;
+            }
 
             // Synchronization primitives
             "os_sync_wait_on_address" => {
diff --git a/src/tools/miri/src/shims/unix/macos/sync.rs b/src/tools/miri/src/shims/unix/macos/sync.rs
index 19f55e6c917..05616dd5a42 100644
--- a/src/tools/miri/src/shims/unix/macos/sync.rs
+++ b/src/tools/miri/src/shims/unix/macos/sync.rs
@@ -68,10 +68,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // LAZY_INIT_COOKIE). This can't be hit via `std::sync::Mutex`.
                 interp_ok(MacOsUnfairLock::Poisoned)
             },
-            |ecx| {
-                let mutex_ref = ecx.machine.sync.mutex_create();
-                interp_ok(MacOsUnfairLock::Active { mutex_ref })
-            },
+            |_| interp_ok(MacOsUnfairLock::Active { mutex_ref: MutexRef::new() }),
         )
     }
 }
diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs
index aefeee6f7a3..1738de4dd4f 100644
--- a/src/tools/miri/src/shims/unix/mem.rs
+++ b/src/tools/miri/src/shims/unix/mem.rs
@@ -49,7 +49,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             && matches!(&*this.tcx.sess.target.os, "macos" | "solaris" | "illumos")
             && (flags & map_fixed) != 0
         {
-            return interp_ok(Scalar::from_maybe_pointer(Pointer::from_addr_invalid(addr), this));
+            return interp_ok(Scalar::from_maybe_pointer(Pointer::without_provenance(addr), this));
         }
 
         let prot_read = this.eval_libc_i32("PROT_READ");
@@ -130,8 +130,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         // addr must be a multiple of the page size, but apart from that munmap is just implemented
         // as a dealloc.
-        #[expect(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero
-        if addr.addr().bytes() % this.machine.page_size != 0 {
+        if !addr.addr().bytes().is_multiple_of(this.machine.page_size) {
             return this.set_last_error_and_return_i32(LibcError("EINVAL"));
         }
 
diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs
index eee2bbcb903..e20e3b79c3b 100644
--- a/src/tools/miri/src/shims/unix/sync.rs
+++ b/src/tools/miri/src/shims/unix/sync.rs
@@ -17,7 +17,7 @@ fn bytewise_equal_atomic_relaxed<'tcx>(
 
     // We do this in chunks of 4, so that we are okay to race with (sufficiently aligned)
     // 4-byte atomic accesses.
-    assert!(size.bytes() % 4 == 0);
+    assert!(size.bytes().is_multiple_of(4));
     for i in 0..(size.bytes() / 4) {
         let offset = Size::from_bytes(i.strict_mul(4));
         let load = |place: &MPlaceTy<'tcx>| {
@@ -171,8 +171,7 @@ fn mutex_create<'tcx>(
     kind: MutexKind,
 ) -> InterpResult<'tcx, PthreadMutex> {
     let mutex = ecx.deref_pointer_as(mutex_ptr, ecx.libc_ty_layout("pthread_mutex_t"))?;
-    let id = ecx.machine.sync.mutex_create();
-    let data = PthreadMutex { mutex_ref: id, kind };
+    let data = PthreadMutex { mutex_ref: MutexRef::new(), kind };
     ecx.lazy_sync_init(&mutex, mutex_init_offset(ecx)?, data.clone())?;
     interp_ok(data)
 }
@@ -193,8 +192,7 @@ where
         || throw_ub_format!("`pthread_mutex_t` can't be moved after first use"),
         |ecx| {
             let kind = mutex_kind_from_static_initializer(ecx, &mutex)?;
-            let id = ecx.machine.sync.mutex_create();
-            interp_ok(PthreadMutex { mutex_ref: id, kind })
+            interp_ok(PthreadMutex { mutex_ref: MutexRef::new(), kind })
         },
     )
 }
@@ -278,8 +276,7 @@ where
             )? {
                 throw_unsup_format!("unsupported static initializer used for `pthread_rwlock_t`");
             }
-            let rwlock_ref = ecx.machine.sync.rwlock_create();
-            interp_ok(PthreadRwLock { rwlock_ref })
+            interp_ok(PthreadRwLock { rwlock_ref: RwLockRef::new() })
         },
     )
 }
@@ -372,9 +369,9 @@ enum ClockId {
     Monotonic,
 }
 
-#[derive(Debug, Copy, Clone)]
+#[derive(Debug, Clone)]
 struct PthreadCondvar {
-    id: CondvarId,
+    condvar_ref: CondvarRef,
     clock: ClockId,
 }
 
@@ -384,9 +381,8 @@ fn cond_create<'tcx>(
     clock: ClockId,
 ) -> InterpResult<'tcx, PthreadCondvar> {
     let cond = ecx.deref_pointer_as(cond_ptr, ecx.libc_ty_layout("pthread_cond_t"))?;
-    let id = ecx.machine.sync.condvar_create();
-    let data = PthreadCondvar { id, clock };
-    ecx.lazy_sync_init(&cond, cond_init_offset(ecx)?, data)?;
+    let data = PthreadCondvar { condvar_ref: CondvarRef::new(), clock };
+    ecx.lazy_sync_init(&cond, cond_init_offset(ecx)?, data.clone())?;
     interp_ok(data)
 }
 
@@ -411,8 +407,7 @@ where
                 throw_unsup_format!("unsupported static initializer used for `pthread_cond_t`");
             }
             // This used the static initializer. The clock there is always CLOCK_REALTIME.
-            let id = ecx.machine.sync.condvar_create();
-            interp_ok(PthreadCondvar { id, clock: ClockId::Realtime })
+            interp_ok(PthreadCondvar { condvar_ref: CondvarRef::new(), clock: ClockId::Realtime })
         },
     )
 }
@@ -817,15 +812,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
     fn pthread_cond_signal(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
-        let id = cond_get_data(this, cond_op)?.id;
-        this.condvar_signal(id)?;
+        let condvar = cond_get_data(this, cond_op)?.condvar_ref.clone();
+        this.condvar_signal(&condvar)?;
         interp_ok(())
     }
 
     fn pthread_cond_broadcast(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
-        let id = cond_get_data(this, cond_op)?.id;
-        while this.condvar_signal(id)? {}
+        let condvar = cond_get_data(this, cond_op)?.condvar_ref.clone();
+        while this.condvar_signal(&condvar)? {}
         interp_ok(())
     }
 
@@ -837,11 +832,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
-        let data = *cond_get_data(this, cond_op)?;
+        let data = cond_get_data(this, cond_op)?.clone();
         let mutex_ref = mutex_get_data(this, mutex_op)?.mutex_ref.clone();
 
         this.condvar_wait(
-            data.id,
+            data.condvar_ref,
             mutex_ref,
             None, // no timeout
             Scalar::from_i32(0),
@@ -861,7 +856,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
-        let data = *cond_get_data(this, cond_op)?;
+        let data = cond_get_data(this, cond_op)?.clone();
         let mutex_ref = mutex_get_data(this, mutex_op)?.mutex_ref.clone();
 
         // Extract the timeout.
@@ -884,7 +879,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         };
 
         this.condvar_wait(
-            data.id,
+            data.condvar_ref,
             mutex_ref,
             Some((timeout_clock, TimeoutAnchor::Absolute, duration)),
             Scalar::from_i32(0),
@@ -900,8 +895,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         // Reading the field also has the side-effect that we detect double-`destroy`
         // since we make the field uninit below.
-        let id = cond_get_data(this, cond_op)?.id;
-        if this.condvar_is_awaited(id) {
+        let condvar = &cond_get_data(this, cond_op)?.condvar_ref;
+        if condvar.is_awaited() {
             throw_ub_format!("destroying an awaited conditional variable");
         }
 
diff --git a/src/tools/miri/src/shims/unix/thread.rs b/src/tools/miri/src/shims/unix/thread.rs
index 4b6615b3ea8..a438e71a41d 100644
--- a/src/tools/miri/src/shims/unix/thread.rs
+++ b/src/tools/miri/src/shims/unix/thread.rs
@@ -41,7 +41,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         &mut self,
         thread: &OpTy<'tcx>,
         retval: &OpTy<'tcx>,
-    ) -> InterpResult<'tcx, Scalar> {
+        return_dest: &MPlaceTy<'tcx>,
+    ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
         if !this.ptr_is_null(this.read_pointer(retval)?)? {
@@ -51,12 +52,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let thread = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?;
         let Ok(thread) = this.thread_id_try_from(thread) else {
-            return interp_ok(this.eval_libc("ESRCH"));
+            this.write_scalar(this.eval_libc("ESRCH"), return_dest)?;
+            return interp_ok(());
         };
 
-        this.join_thread_exclusive(thread)?;
-
-        interp_ok(Scalar::from_u32(0))
+        this.join_thread_exclusive(
+            thread,
+            /* success_retval */ Scalar::from_u32(0),
+            return_dest,
+        )
     }
 
     fn pthread_detach(&mut self, thread: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index 10f6df67ad4..959abc0baca 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -573,8 +573,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "WaitForSingleObject" => {
                 let [handle, timeout] = this.check_shim(abi, sys_conv, link_name, args)?;
 
-                let ret = this.WaitForSingleObject(handle, timeout)?;
-                this.write_scalar(ret, dest)?;
+                this.WaitForSingleObject(handle, timeout, dest)?;
             }
             "GetCurrentProcess" => {
                 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
@@ -630,6 +629,23 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(name, &name_ptr)?;
                 this.write_scalar(res, dest)?;
             }
+            "GetThreadId" => {
+                let [handle] = this.check_shim(abi, sys_conv, link_name, args)?;
+                let handle = this.read_handle(handle, "GetThreadId")?;
+                let thread = match handle {
+                    Handle::Thread(thread) => thread,
+                    Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
+                    _ => this.invalid_handle("GetThreadDescription")?,
+                };
+                let tid = this.get_tid(thread);
+                this.write_scalar(Scalar::from_u32(tid), dest)?;
+            }
+            "GetCurrentThreadId" => {
+                let [] = this.check_shim(abi, sys_conv, link_name, args)?;
+                let thread = this.active_thread();
+                let tid = this.get_tid(thread);
+                this.write_scalar(Scalar::from_u32(tid), dest)?;
+            }
 
             // Miscellaneous
             "ExitProcess" => {
diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs
index 1e30bf25ed9..8a965ea316d 100644
--- a/src/tools/miri/src/shims/windows/handle.rs
+++ b/src/tools/miri/src/shims/windows/handle.rs
@@ -166,6 +166,10 @@ impl Handle {
     /// Structurally invalid handles return [`HandleError::InvalidHandle`].
     /// If the handle is structurally valid but semantically invalid, e.g. a for non-existent thread
     /// ID, returns [`HandleError::ThreadNotFound`].
+    ///
+    /// This function is deliberately private; shims should always use `read_handle`.
+    /// That enforces handle validity even when Windows does not: for now, we argue invalid
+    /// handles are always a bug and programmers likely want to know about them.
     fn try_from_scalar<'tcx>(
         handle: Scalar,
         cx: &MiriInterpCx<'tcx>,
diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs
index 8d5ea7db9e4..9165e76b63d 100644
--- a/src/tools/miri/src/shims/windows/sync.rs
+++ b/src/tools/miri/src/shims/windows/sync.rs
@@ -2,13 +2,13 @@ use std::time::Duration;
 
 use rustc_abi::Size;
 
-use crate::concurrency::init_once::InitOnceStatus;
+use crate::concurrency::init_once::{EvalContextExt as _, InitOnceStatus};
 use crate::concurrency::sync::FutexRef;
 use crate::*;
 
-#[derive(Copy, Clone)]
+#[derive(Clone)]
 struct WindowsInitOnce {
-    id: InitOnceId,
+    init_once: InitOnceRef,
 }
 
 struct WindowsFutex {
@@ -37,10 +37,9 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             &init_once,
             init_offset,
             || throw_ub_format!("`INIT_ONCE` can't be moved after first use"),
-            |this| {
+            |_| {
                 // TODO: check that this is still all-zero.
-                let id = this.machine.sync.init_once_create();
-                interp_ok(WindowsInitOnce { id })
+                interp_ok(WindowsInitOnce { init_once: InitOnceRef::new() })
             },
         )
     }
@@ -48,20 +47,20 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
     /// Returns `true` if we were succssful, `false` if we would block.
     fn init_once_try_begin(
         &mut self,
-        id: InitOnceId,
+        init_once_ref: &InitOnceRef,
         pending_place: &MPlaceTy<'tcx>,
         dest: &MPlaceTy<'tcx>,
     ) -> InterpResult<'tcx, bool> {
         let this = self.eval_context_mut();
-        interp_ok(match this.init_once_status(id) {
+        interp_ok(match init_once_ref.status() {
             InitOnceStatus::Uninitialized => {
-                this.init_once_begin(id);
+                init_once_ref.begin();
                 this.write_scalar(this.eval_windows("c", "TRUE"), pending_place)?;
                 this.write_scalar(this.eval_windows("c", "TRUE"), dest)?;
                 true
             }
             InitOnceStatus::Complete => {
-                this.init_once_observe_completed(id);
+                this.init_once_observe_completed(init_once_ref);
                 this.write_scalar(this.eval_windows("c", "FALSE"), pending_place)?;
                 this.write_scalar(this.eval_windows("c", "TRUE"), dest)?;
                 true
@@ -84,7 +83,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
-        let id = this.init_once_get_data(init_once_op)?.id;
+        let init_once = this.init_once_get_data(init_once_op)?.init_once.clone();
         let flags = this.read_scalar(flags_op)?.to_u32()?;
         // PBOOL is int*
         let pending_place = this.deref_pointer_as(pending_op, this.machine.layouts.i32)?;
@@ -98,7 +97,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             throw_unsup_format!("non-null `lpContext` in `InitOnceBeginInitialize`");
         }
 
-        if this.init_once_try_begin(id, &pending_place, dest)? {
+        if this.init_once_try_begin(&init_once, &pending_place, dest)? {
             // Done!
             return interp_ok(());
         }
@@ -106,16 +105,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // We have to block, and then try again when we are woken up.
         let dest = dest.clone();
         this.init_once_enqueue_and_block(
-            id,
+            init_once.clone(),
             callback!(
                 @capture<'tcx> {
-                    id: InitOnceId,
+                    init_once: InitOnceRef,
                     pending_place: MPlaceTy<'tcx>,
                     dest: MPlaceTy<'tcx>,
                 }
                 |this, unblock: UnblockKind| {
                     assert_eq!(unblock, UnblockKind::Ready);
-                    let ret = this.init_once_try_begin(id, &pending_place, &dest)?;
+                    let ret = this.init_once_try_begin(&init_once, &pending_place, &dest)?;
                     assert!(ret, "we were woken up but init_once_try_begin still failed");
                     interp_ok(())
                 }
@@ -132,7 +131,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
-        let id = this.init_once_get_data(init_once_op)?.id;
+        let init_once = this.init_once_get_data(init_once_op)?.init_once.clone();
         let flags = this.read_scalar(flags_op)?.to_u32()?;
         let context = this.read_pointer(context_op)?;
 
@@ -148,7 +147,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             throw_unsup_format!("non-null `lpContext` in `InitOnceBeginInitialize`");
         }
 
-        if this.init_once_status(id) != InitOnceStatus::Begun {
+        if init_once.status() != InitOnceStatus::Begun {
             // The docs do not say anything about this case, but it seems better to not allow it.
             throw_ub_format!(
                 "calling InitOnceComplete on a one time initialization that has not begun or is already completed"
@@ -156,9 +155,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         }
 
         if success {
-            this.init_once_complete(id)?;
+            this.init_once_complete(&init_once)?;
         } else {
-            this.init_once_fail(id)?;
+            this.init_once_fail(&init_once)?;
         }
 
         interp_ok(this.eval_windows("c", "TRUE"))
diff --git a/src/tools/miri/src/shims/windows/thread.rs b/src/tools/miri/src/shims/windows/thread.rs
index 56ae88bb1a1..a155ec65a51 100644
--- a/src/tools/miri/src/shims/windows/thread.rs
+++ b/src/tools/miri/src/shims/windows/thread.rs
@@ -58,13 +58,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         &mut self,
         handle_op: &OpTy<'tcx>,
         timeout_op: &OpTy<'tcx>,
-    ) -> InterpResult<'tcx, Scalar> {
+        return_dest: &MPlaceTy<'tcx>,
+    ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
         let handle = this.read_handle(handle_op, "WaitForSingleObject")?;
         let timeout = this.read_scalar(timeout_op)?.to_u32()?;
 
-        let thread = match handle {
+        let joined_thread_id = match handle {
             Handle::Thread(thread) => thread,
             // Unlike on posix, the outcome of joining the current thread is not documented.
             // On current Windows, it just deadlocks.
@@ -76,8 +77,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             throw_unsup_format!("`WaitForSingleObject` with non-infinite timeout");
         }
 
-        this.join_thread(thread)?;
+        this.join_thread(
+            joined_thread_id,
+            /* success_retval */ this.eval_windows("c", "WAIT_OBJECT_0"),
+            return_dest,
+        )?;
 
-        interp_ok(this.eval_windows("c", "WAIT_OBJECT_0"))
+        interp_ok(())
     }
 }
diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_thread_invalid.rs b/src/tools/miri/tests/fail-dep/concurrency/windows_thread_invalid.rs
new file mode 100644
index 00000000000..2e0729c9b49
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/concurrency/windows_thread_invalid.rs
@@ -0,0 +1,9 @@
+//! Ensure we error if thread functions are called with invalid handles
+//@only-target: windows # testing Windows API
+
+use windows_sys::Win32::System::Threading::GetThreadId;
+
+fn main() {
+    let _tid = unsafe { GetThreadId(std::ptr::dangling_mut()) };
+    //~^ ERROR: invalid handle
+}
diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_thread_invalid.stderr b/src/tools/miri/tests/fail-dep/concurrency/windows_thread_invalid.stderr
new file mode 100644
index 00000000000..8d4b049b740
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/concurrency/windows_thread_invalid.stderr
@@ -0,0 +1,13 @@
+error: abnormal termination: invalid handle 1 passed to GetThreadId
+  --> tests/fail-dep/concurrency/windows_thread_invalid.rs:LL:CC
+   |
+LL |     let _tid = unsafe { GetThreadId(std::ptr::dangling_mut()) };
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here
+   |
+   = note: BACKTRACE:
+   = note: inside `main` at tests/fail-dep/concurrency/windows_thread_invalid.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs
index dd2dd346231..1dc334486c3 100644
--- a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs
+++ b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs
@@ -20,7 +20,7 @@ fn main() {
         let mut buf: MaybeUninit<[u8; 4]> = std::mem::MaybeUninit::uninit();
         // Read 4 bytes from a 3-byte file.
         assert_eq!(libc::read(fd, buf.as_mut_ptr().cast::<std::ffi::c_void>(), 4), 3);
-        buf.assume_init(); //~ERROR: Undefined Behavior: constructing invalid value at .value[3]: encountered uninitialized memory, but expected an integer
+        buf.assume_init(); //~ERROR: encountered uninitialized memory, but expected an integer
         assert_eq!(libc::close(fd), 0);
     }
     remove_file(&path).unwrap();
diff --git a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr
index fadb31e3a8f..83119f087ff 100644
--- a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: constructing invalid value at .value[3]: encountered uninitialized memory, but expected an integer
+error: Undefined Behavior: constructing invalid value at [3]: encountered uninitialized memory, but expected an integer
   --> tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs:LL:CC
    |
-LL | ...   buf.assume_init();
-   |       ^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
+LL |         buf.assume_init();
+   |         ^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs
index c63e926376d..9646cdb2065 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs
@@ -6,7 +6,7 @@ fn direct_raw(x: *const (i32, i32)) -> *const i32 {
 
 // Ensure that if a raw pointer is created via an intermediate
 // reference, we catch that. (Just in case someone decides to
-// desugar this differenly or so.)
+// desugar this differently or so.)
 fn via_ref(x: *const (i32, i32)) -> *const i32 {
     unsafe { &(*x).0 as *const i32 } //~ERROR: dangling pointer
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs
index dd3246d8120..34fef6b9ee5 100644
--- a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs
+++ b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs
@@ -1,11 +1,6 @@
-//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()"
-//@normalize-stderr-test: "\| +\^+" -> "| ^"
-//@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> ""
-//@normalize-stderr-test: "\n +at [^\n]+" -> ""
-//@error-in-other-file: aborted execution
 #![feature(never_type)]
 
 #[allow(deprecated, invalid_value)]
 fn main() {
-    let _ = unsafe { std::mem::uninitialized::<!>() };
+    let _ = unsafe { std::mem::uninitialized::<!>() }; //~ERROR: constructing invalid value
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr
index 3db8a5be205..36642208afe 100644
--- a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr
@@ -1,27 +1,13 @@
-
-thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC:
-aborted execution: attempted to instantiate uninhabited type `!`
-note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
-thread caused non-unwinding panic. aborting.
-error: abnormal termination: the program aborted execution
-  --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
-   |
-LL | ABORT()
-   | ^ abnormal termination occurred here
-   |
-   = note: BACKTRACE:
-   = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
-   = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
-   = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC
-note: inside `main`
+error: Undefined Behavior: constructing invalid value: encountered a value of the never type `!`
   --> tests/fail/intrinsics/uninit_uninhabited_type.rs:LL:CC
    |
 LL |     let _ = unsafe { std::mem::uninitialized::<!>() };
-   | ^
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at tests/fail/intrinsics/uninit_uninhabited_type.rs:LL:CC
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
diff --git a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs
index 3d355bad626..cca2c5ae984 100644
--- a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs
+++ b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs
@@ -1,10 +1,4 @@
-//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()"
-//@normalize-stderr-test: "\| +\^+" -> "| ^"
-//@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> ""
-//@normalize-stderr-test: "\n +at [^\n]+" -> ""
-//@error-in-other-file: aborted execution
-
 #[allow(deprecated, invalid_value)]
 fn main() {
-    let _ = unsafe { std::mem::zeroed::<fn()>() };
+    let _ = unsafe { std::mem::zeroed::<fn()>() }; //~ERROR: constructing invalid value
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr
index a1e476328b0..53f3f8d1404 100644
--- a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr
@@ -1,27 +1,13 @@
-
-thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC:
-aborted execution: attempted to zero-initialize type `fn()`, which is invalid
-note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
-thread caused non-unwinding panic. aborting.
-error: abnormal termination: the program aborted execution
-  --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
-   |
-LL | ABORT()
-   | ^ abnormal termination occurred here
-   |
-   = note: BACKTRACE:
-   = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
-   = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
-   = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC
-note: inside `main`
+error: Undefined Behavior: constructing invalid value: encountered a null function pointer
   --> tests/fail/intrinsics/zero_fn_ptr.rs:LL:CC
    |
 LL |     let _ = unsafe { std::mem::zeroed::<fn()>() };
-   | ^
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at tests/fail/intrinsics/zero_fn_ptr.rs:LL:CC
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
diff --git a/src/tools/miri/tests/fail/validity/uninit_float.stderr b/src/tools/miri/tests/fail/validity/uninit_float.stderr
index 1b948b062e1..0c859d72764 100644
--- a/src/tools/miri/tests/fail/validity/uninit_float.stderr
+++ b/src/tools/miri/tests/fail/validity/uninit_float.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized memory, but expected a floating point number
+error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected a floating point number
   --> tests/fail/validity/uninit_float.rs:LL:CC
    |
 LL |     let _val: [f32; 1] = unsafe { std::mem::uninitialized() };
diff --git a/src/tools/miri/tests/fail/validity/uninit_integer.stderr b/src/tools/miri/tests/fail/validity/uninit_integer.stderr
index b17bdee65da..5d31e2659ee 100644
--- a/src/tools/miri/tests/fail/validity/uninit_integer.stderr
+++ b/src/tools/miri/tests/fail/validity/uninit_integer.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized memory, but expected an integer
+error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected an integer
   --> tests/fail/validity/uninit_integer.rs:LL:CC
    |
 LL |     let _val = unsafe { std::mem::MaybeUninit::<[usize; 1]>::uninit().assume_init() };
diff --git a/src/tools/miri/tests/fail/validity/uninit_raw_ptr.stderr b/src/tools/miri/tests/fail/validity/uninit_raw_ptr.stderr
index 269af6061c2..d2e9408adbe 100644
--- a/src/tools/miri/tests/fail/validity/uninit_raw_ptr.stderr
+++ b/src/tools/miri/tests/fail/validity/uninit_raw_ptr.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized memory, but expected a raw pointer
+error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected a raw pointer
   --> tests/fail/validity/uninit_raw_ptr.rs:LL:CC
    |
 LL |     let _val = unsafe { std::mem::MaybeUninit::<[*const u8; 1]>::uninit().assume_init() };
diff --git a/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs b/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs
index 3ccfecc6fb3..4c852135367 100644
--- a/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs
+++ b/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs
@@ -1,7 +1,3 @@
-// Only works on Unix targets
-//@ignore-target: windows wasm
-//@only-on-host
-
 fn main() {
     test_access_pointer();
     test_access_simple();
diff --git a/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs b/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs
index bd4e0b23601..86a9c97f4ce 100644
--- a/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs
+++ b/src/tools/miri/tests/native-lib/pass/ptr_write_access.rs
@@ -1,6 +1,3 @@
-// Only works on Unix targets
-//@ignore-target: windows wasm
-//@only-on-host
 //@compile-flags: -Zmiri-permissive-provenance
 
 #![feature(box_as_ptr)]
diff --git a/src/tools/miri/tests/native-lib/pass/scalar_arguments.rs b/src/tools/miri/tests/native-lib/pass/scalar_arguments.rs
index c896bd8dd34..9e99977a692 100644
--- a/src/tools/miri/tests/native-lib/pass/scalar_arguments.rs
+++ b/src/tools/miri/tests/native-lib/pass/scalar_arguments.rs
@@ -1,7 +1,3 @@
-// Only works on Unix targets
-//@ignore-target: windows wasm
-//@only-on-host
-
 extern "C" {
     fn add_one_int(x: i32) -> i32;
     fn add_int16(x: i16) -> i16;
diff --git a/src/tools/miri/tests/native-lib/scalar_arguments.c b/src/tools/miri/tests/native-lib/scalar_arguments.c
index acccf06f3df..8cf38f74413 100644
--- a/src/tools/miri/tests/native-lib/scalar_arguments.c
+++ b/src/tools/miri/tests/native-lib/scalar_arguments.c
@@ -22,11 +22,11 @@ EXPORT uint32_t get_unsigned_int(void) {
   return -10;
 }
 
-EXPORT short add_int16(int16_t x) {
+EXPORT int16_t add_int16(int16_t x) {
   return x + 3;
 }
 
-EXPORT long add_short_to_long(int16_t x, int64_t y) {
+EXPORT int64_t add_short_to_long(int16_t x, int64_t y) {
   return x + y;
 }
 
diff --git a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs
index f8f1c554f0d..19d86f09595 100644
--- a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs
+++ b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs
@@ -33,6 +33,11 @@ fn wake_nobody() {
             0,
         );
     }
+
+    // Wake u32::MAX waiters.
+    unsafe {
+        assert_eq!(libc::syscall(libc::SYS_futex, addr_of!(futex), libc::FUTEX_WAKE, u32::MAX), 0);
+    }
 }
 
 fn wake_dangling() {
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-time.rs b/src/tools/miri/tests/pass-dep/libc/libc-time.rs
index e53201e0bc5..e8957846ad5 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-time.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-time.rs
@@ -1,5 +1,6 @@
 //@ignore-target: windows # no libc time APIs on Windows
 //@compile-flags: -Zmiri-disable-isolation
+use std::time::{Duration, Instant};
 use std::{env, mem, ptr};
 
 fn main() {
@@ -20,6 +21,19 @@ fn main() {
     test_localtime_r_future_32b();
     #[cfg(target_pointer_width = "64")]
     test_localtime_r_future_64b();
+
+    test_nanosleep();
+    #[cfg(any(
+        target_os = "freebsd",
+        target_os = "linux",
+        target_os = "android",
+        target_os = "solaris",
+        target_os = "illumos"
+    ))]
+    {
+        test_clock_nanosleep::absolute();
+        test_clock_nanosleep::relative();
+    }
 }
 
 /// Tests whether clock support exists at all
@@ -315,3 +329,103 @@ fn test_localtime_r_multiple_calls_deduplication() {
         NUM_CALLS - 1
     );
 }
+
+fn test_nanosleep() {
+    let start_test_sleep = Instant::now();
+    let duration_zero = libc::timespec { tv_sec: 0, tv_nsec: 0 };
+    let remainder = ptr::null_mut::<libc::timespec>();
+    let is_error = unsafe { libc::nanosleep(&duration_zero, remainder) };
+    assert_eq!(is_error, 0);
+    assert!(start_test_sleep.elapsed() < Duration::from_millis(10));
+
+    let start_test_sleep = Instant::now();
+    let duration_100_millis = libc::timespec { tv_sec: 0, tv_nsec: 1_000_000_000 / 10 };
+    let remainder = ptr::null_mut::<libc::timespec>();
+    let is_error = unsafe { libc::nanosleep(&duration_100_millis, remainder) };
+    assert_eq!(is_error, 0);
+    assert!(start_test_sleep.elapsed() > Duration::from_millis(100));
+}
+
+#[cfg(any(
+    target_os = "freebsd",
+    target_os = "linux",
+    target_os = "android",
+    target_os = "solaris",
+    target_os = "illumos"
+))]
+mod test_clock_nanosleep {
+    use super::*;
+
+    /// Helper function used to create an instant in the future
+    fn add_100_millis(mut ts: libc::timespec) -> libc::timespec {
+        // While tv_nsec has type `c_long` tv_sec has type `time_t`. These might
+        // end up as different types (for example: like i32 and i64).
+        const SECOND: libc::c_long = 1_000_000_000;
+        ts.tv_nsec += SECOND / 10;
+        // If this pushes tv_nsec to SECOND or higher, we need to overflow to tv_sec.
+        ts.tv_sec += (ts.tv_nsec / SECOND) as libc::time_t;
+        ts.tv_nsec %= SECOND;
+        ts
+    }
+
+    /// Helper function to get the current time for testing relative sleeps
+    fn timespec_now(clock: libc::clockid_t) -> libc::timespec {
+        let mut timespec = mem::MaybeUninit::<libc::timespec>::uninit();
+        let is_error = unsafe { libc::clock_gettime(clock, timespec.as_mut_ptr()) };
+        assert_eq!(is_error, 0);
+        unsafe { timespec.assume_init() }
+    }
+
+    pub fn absolute() {
+        let start_test_sleep = Instant::now();
+        let before_start = libc::timespec { tv_sec: 0, tv_nsec: 0 };
+        let remainder = ptr::null_mut::<libc::timespec>();
+        let error = unsafe {
+            // this will not sleep since unix time zero is in the past
+            libc::clock_nanosleep(
+                libc::CLOCK_MONOTONIC,
+                libc::TIMER_ABSTIME,
+                &before_start,
+                remainder,
+            )
+        };
+        assert_eq!(error, 0);
+        assert!(start_test_sleep.elapsed() < Duration::from_millis(10));
+
+        let start_test_sleep = Instant::now();
+        let hunderd_millis_after_start = add_100_millis(timespec_now(libc::CLOCK_MONOTONIC));
+        let remainder = ptr::null_mut::<libc::timespec>();
+        let error = unsafe {
+            libc::clock_nanosleep(
+                libc::CLOCK_MONOTONIC,
+                libc::TIMER_ABSTIME,
+                &hunderd_millis_after_start,
+                remainder,
+            )
+        };
+        assert_eq!(error, 0);
+        assert!(start_test_sleep.elapsed() > Duration::from_millis(100));
+    }
+
+    pub fn relative() {
+        const NO_FLAGS: i32 = 0;
+
+        let start_test_sleep = Instant::now();
+        let duration_zero = libc::timespec { tv_sec: 0, tv_nsec: 0 };
+        let remainder = ptr::null_mut::<libc::timespec>();
+        let error = unsafe {
+            libc::clock_nanosleep(libc::CLOCK_MONOTONIC, NO_FLAGS, &duration_zero, remainder)
+        };
+        assert_eq!(error, 0);
+        assert!(start_test_sleep.elapsed() < Duration::from_millis(10));
+
+        let start_test_sleep = Instant::now();
+        let duration_100_millis = libc::timespec { tv_sec: 0, tv_nsec: 1_000_000_000 / 10 };
+        let remainder = ptr::null_mut::<libc::timespec>();
+        let error = unsafe {
+            libc::clock_nanosleep(libc::CLOCK_MONOTONIC, NO_FLAGS, &duration_100_millis, remainder)
+        };
+        assert_eq!(error, 0);
+        assert!(start_test_sleep.elapsed() > Duration::from_millis(100));
+    }
+}
diff --git a/src/tools/miri/tests/pass-dep/shims/gettid.rs b/src/tools/miri/tests/pass-dep/shims/gettid.rs
new file mode 100644
index 00000000000..b7a2fa49ef8
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/shims/gettid.rs
@@ -0,0 +1,183 @@
+//! Test for `gettid` and similar functions for retrieving an OS thread ID.
+//@ revisions: with_isolation without_isolation
+//@ [without_isolation] compile-flags: -Zmiri-disable-isolation
+
+#![feature(linkage)]
+
+fn gettid() -> u64 {
+    cfg_if::cfg_if! {
+        if #[cfg(any(target_os = "android", target_os = "linux"))] {
+            gettid_linux_like()
+        } else if #[cfg(target_os = "nto")] {
+            unsafe { libc::gettid() as u64 }
+        } else if #[cfg(target_os = "openbsd")] {
+            unsafe { libc::getthrid() as u64 }
+        } else if #[cfg(target_os = "freebsd")] {
+            unsafe { libc::pthread_getthreadid_np() as u64 }
+        } else if #[cfg(target_os = "netbsd")] {
+            unsafe { libc::_lwp_self() as u64 }
+        } else if #[cfg(any(target_os = "solaris", target_os = "illumos"))] {
+            // On Solaris and Illumos, the `pthread_t` is the OS TID.
+            unsafe { libc::pthread_self() as u64 }
+        } else if #[cfg(target_vendor = "apple")] {
+            let mut id = 0u64;
+            let status: libc::c_int = unsafe { libc::pthread_threadid_np(0, &mut id) };
+            assert_eq!(status, 0);
+            id
+        } else if #[cfg(windows)] {
+            use windows_sys::Win32::System::Threading::GetCurrentThreadId;
+            unsafe { GetCurrentThreadId() as u64 }
+        } else {
+            compile_error!("platform has no gettid")
+        }
+    }
+}
+
+/// Test the libc function, the syscall, and the extern symbol.
+#[cfg(any(target_os = "android", target_os = "linux"))]
+fn gettid_linux_like() -> u64 {
+    unsafe extern "C" {
+        #[linkage = "extern_weak"]
+        static gettid: Option<unsafe extern "C" fn() -> libc::pid_t>;
+    }
+
+    let from_libc = unsafe { libc::gettid() as u64 };
+    let from_sys = unsafe { libc::syscall(libc::SYS_gettid) as u64 };
+    let from_static = unsafe { gettid.unwrap()() as u64 };
+
+    assert_eq!(from_libc, from_sys);
+    assert_eq!(from_libc, from_static);
+
+    from_libc
+}
+
+/// Specific platforms can query the tid of arbitrary threads from a `pthread_t` / `HANDLE`
+#[cfg(any(target_vendor = "apple", windows))]
+mod queried {
+    use std::ffi::c_void;
+    use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
+    use std::{ptr, thread};
+
+    use super::*;
+
+    static SPAWNED_TID: AtomicU64 = AtomicU64::new(0);
+    static CAN_JOIN: AtomicBool = AtomicBool::new(false);
+
+    /// Save this thread's TID, give the spawning thread a chance to query it separately before
+    /// being joined.
+    fn thread_body() {
+        SPAWNED_TID.store(gettid(), Ordering::Relaxed);
+
+        // Spin until the main thread has a chance to read this thread's ID
+        while !CAN_JOIN.load(Ordering::Relaxed) {
+            thread::yield_now();
+        }
+    }
+
+    /// Spawn a thread, query then return its TID.
+    #[cfg(target_vendor = "apple")]
+    fn spawn_update_join() -> u64 {
+        extern "C" fn thread_start(_data: *mut c_void) -> *mut c_void {
+            thread_body();
+            ptr::null_mut()
+        }
+
+        let mut t: libc::pthread_t = 0;
+        let mut spawned_tid_from_handle = 0u64;
+
+        unsafe {
+            let res = libc::pthread_create(&mut t, ptr::null(), thread_start, ptr::null_mut());
+            assert_eq!(res, 0, "failed to spawn thread");
+
+            let res = libc::pthread_threadid_np(t, &mut spawned_tid_from_handle);
+            assert_eq!(res, 0, "failed to query thread ID");
+            CAN_JOIN.store(true, Ordering::Relaxed);
+
+            let res = libc::pthread_join(t, ptr::null_mut());
+            assert_eq!(res, 0, "failed to join thread");
+
+            // Apple also has two documented return values for invalid threads and null pointers
+            let res = libc::pthread_threadid_np(libc::pthread_t::MAX, &mut 0);
+            assert_eq!(res, libc::ESRCH, "expected ESRCH for invalid TID");
+            let res = libc::pthread_threadid_np(0, ptr::null_mut());
+            assert_eq!(res, libc::EINVAL, "invalid EINVAL for a null pointer");
+        }
+
+        spawned_tid_from_handle
+    }
+
+    /// Spawn a thread, query then return its TID.
+    #[cfg(windows)]
+    fn spawn_update_join() -> u64 {
+        use windows_sys::Win32::Foundation::WAIT_FAILED;
+        use windows_sys::Win32::System::Threading::{
+            CreateThread, GetThreadId, INFINITE, WaitForSingleObject,
+        };
+
+        extern "system" fn thread_start(_data: *mut c_void) -> u32 {
+            thread_body();
+            0
+        }
+
+        let spawned_tid_from_handle;
+        let mut tid_at_spawn = 0u32;
+
+        unsafe {
+            let handle =
+                CreateThread(ptr::null(), 0, Some(thread_start), ptr::null(), 0, &mut tid_at_spawn);
+            assert!(!handle.is_null(), "failed to spawn thread");
+
+            spawned_tid_from_handle = GetThreadId(handle);
+            assert_ne!(spawned_tid_from_handle, 0, "failed to query thread ID");
+            CAN_JOIN.store(true, Ordering::Relaxed);
+
+            let res = WaitForSingleObject(handle, INFINITE);
+            assert_ne!(res, WAIT_FAILED, "failed to join thread");
+        }
+
+        // Windows also indirectly returns the TID from `CreateThread`, ensure that matches up.
+        assert_eq!(spawned_tid_from_handle, tid_at_spawn);
+
+        spawned_tid_from_handle.into()
+    }
+
+    pub fn check() {
+        let spawned_tid_from_handle = spawn_update_join();
+        let spawned_tid_from_self = SPAWNED_TID.load(Ordering::Relaxed);
+        let current_tid = gettid();
+
+        // Ensure that we got a different thread ID.
+        assert_ne!(spawned_tid_from_handle, current_tid);
+
+        // Ensure that we get the same result from `gettid` and from querying a thread's handle
+        assert_eq!(spawned_tid_from_handle, spawned_tid_from_self);
+    }
+}
+
+fn main() {
+    let tid = gettid();
+
+    std::thread::spawn(move || {
+        assert_ne!(gettid(), tid);
+    });
+
+    // Test that in isolation mode a deterministic value will be returned.
+    // The value is not important, we only care that whatever the value is,
+    // won't change from execution to execution.
+    if cfg!(with_isolation) {
+        if cfg!(target_os = "linux") {
+            // Linux starts the TID at the PID, which is 1000.
+            assert_eq!(tid, 1000);
+        } else {
+            // Other platforms start counting from 0.
+            assert_eq!(tid, 0);
+        }
+    }
+
+    // On Linux and NetBSD, the first TID is the PID.
+    #[cfg(any(target_os = "linux", target_os = "netbsd"))]
+    assert_eq!(tid, unsafe { libc::getpid() } as u64);
+
+    #[cfg(any(target_vendor = "apple", windows))]
+    queried::check();
+}
diff --git a/src/tools/miri/tests/pass/alloc-access-tracking.rs b/src/tools/miri/tests/pass/alloc-access-tracking.rs
index 9eba0ca171b..0e88951dc43 100644
--- a/src/tools/miri/tests/pass/alloc-access-tracking.rs
+++ b/src/tools/miri/tests/pass/alloc-access-tracking.rs
@@ -1,7 +1,7 @@
 #![no_std]
 #![no_main]
-//@compile-flags: -Zmiri-track-alloc-id=19 -Zmiri-track-alloc-accesses -Cpanic=abort
-//@normalize-stderr-test: "id 19" -> "id $$ALLOC"
+//@compile-flags: -Zmiri-track-alloc-id=20 -Zmiri-track-alloc-accesses -Cpanic=abort
+//@normalize-stderr-test: "id 20" -> "id $$ALLOC"
 //@only-target: linux # alloc IDs differ between OSes (due to extern static allocations)
 
 extern "Rust" {
diff --git a/src/tools/miri/tests/pass/dyn-star.rs b/src/tools/miri/tests/pass/dyn-star.rs
deleted file mode 100644
index 1ce0dd3c9d5..00000000000
--- a/src/tools/miri/tests/pass/dyn-star.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-#![feature(dyn_star)]
-#![allow(incomplete_features)]
-#![feature(custom_inner_attributes)]
-// rustfmt destroys `dyn* Trait` syntax
-#![rustfmt::skip]
-
-use std::fmt::{Debug, Display};
-
-fn main() {
-    make_dyn_star();
-    method();
-    box_();
-    dispatch_on_pin_mut();
-    dyn_star_to_dyn();
-    dyn_to_dyn_star();
-}
-
-fn dyn_star_to_dyn() {
-    let x: dyn* Debug = &42;
-    let x = Box::new(x) as Box<dyn Debug>;
-    assert_eq!("42", format!("{x:?}"));
-}
-
-fn dyn_to_dyn_star() {
-    let x: Box<dyn Debug> = Box::new(42);
-    let x = &x as dyn* Debug;
-    assert_eq!("42", format!("{x:?}"));
-}
-
-fn make_dyn_star() {
-    fn make_dyn_star_coercion(i: usize) {
-        let _dyn_i: dyn* Debug = i;
-    }
-
-    fn make_dyn_star_explicit(i: usize) {
-        let _dyn_i: dyn* Debug = i as dyn* Debug;
-    }
-
-    make_dyn_star_coercion(42);
-    make_dyn_star_explicit(42);
-}
-
-fn method() {
-    trait Foo {
-        fn get(&self) -> usize;
-    }
-    
-    impl Foo for usize {
-        fn get(&self) -> usize {
-            *self
-        }
-    }
-    
-    fn invoke_dyn_star(i: dyn* Foo) -> usize {
-        i.get()
-    }
-    
-    fn make_and_invoke_dyn_star(i: usize) -> usize {
-        let dyn_i: dyn* Foo = i;
-        invoke_dyn_star(dyn_i)
-    }
-    
-    assert_eq!(make_and_invoke_dyn_star(42), 42);
-}
-
-fn box_() {
-    fn make_dyn_star() -> dyn* Display {
-        Box::new(42) as dyn* Display
-    }
-    
-    let x = make_dyn_star();
-    assert_eq!(format!("{x}"), "42");
-}
-
-fn dispatch_on_pin_mut() {
-    use std::future::Future;
-
-    async fn foo(f: dyn* Future<Output = i32>) {
-        println!("dispatch_on_pin_mut: value: {}", f.await);
-    }
-
-    async fn async_main() {
-        foo(Box::pin(async { 1 })).await
-    }
-
-    // ------------------------------------------------------------------------- //
-    // Implementation Details Below...
-
-    use std::pin::Pin;
-    use std::task::*;
-
-    let mut fut = async_main();
-
-    // Poll loop, just to test the future...
-    let ctx = &mut Context::from_waker(Waker::noop());
-
-    loop {
-        match unsafe { Pin::new_unchecked(&mut fut).poll(ctx) } {
-            Poll::Pending => {}
-            Poll::Ready(()) => break,
-        }
-    }
-}
diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs
index 383579198bb..fe7316c6680 100644
--- a/src/tools/miri/tests/pass/float.rs
+++ b/src/tools/miri/tests/pass/float.rs
@@ -1066,18 +1066,6 @@ pub fn libm() {
     assert_eq!((-1f32).powf(f32::NEG_INFINITY), 1.0);
     assert_eq!((-1f64).powf(f64::NEG_INFINITY), 1.0);
 
-    // For pow (powf in rust) the C standard says:
-    // x^0 = 1 for all x even a sNaN
-    // FIXME(#4286): this does not match the behavior of all implementations.
-    assert_eq!(SNAN_F32.powf(0.0), 1.0);
-    assert_eq!(SNAN_F64.powf(0.0), 1.0);
-
-    // For pown (powi in rust) the C standard says:
-    // x^0 = 1 for all x even a sNaN
-    // FIXME(#4286): this does not match the behavior of all implementations.
-    assert_eq!(SNAN_F32.powi(0), 1.0);
-    assert_eq!(SNAN_F64.powi(0), 1.0);
-
     assert_eq!(0f32.powi(10), 0.0);
     assert_eq!(0f64.powi(100), 0.0);
     assert_eq!(0f32.powi(9), 0.0);
@@ -1358,7 +1346,7 @@ fn test_min_max_nondet() {
     /// Ensure that if we call the closure often enough, we see both `true` and `false.`
     #[track_caller]
     fn ensure_both(f: impl Fn() -> bool) {
-        let rounds = 16;
+        let rounds = 32;
         let first = f();
         for _ in 1..rounds {
             if f() != first {
@@ -1500,4 +1488,17 @@ fn test_non_determinism() {
     test_operations_f32(12., 5.);
     test_operations_f64(19., 11.);
     test_operations_f128(25., 18.);
+
+    // SNaN^0 = (1 | NaN)
+    ensure_nondet(|| f32::powf(SNAN_F32, 0.0).is_nan());
+    ensure_nondet(|| f64::powf(SNAN_F64, 0.0).is_nan());
+
+    // 1^SNaN = (1 | NaN)
+    ensure_nondet(|| f32::powf(1.0, SNAN_F32).is_nan());
+    ensure_nondet(|| f64::powf(1.0, SNAN_F64).is_nan());
+
+    // same as powf (keep it consistent):
+    // x^SNaN = (1 | NaN)
+    ensure_nondet(|| f32::powi(SNAN_F32, 0).is_nan());
+    ensure_nondet(|| f64::powi(SNAN_F64, 0).is_nan());
 }
diff --git a/src/tools/miri/tests/pass/float_nan.rs b/src/tools/miri/tests/pass/float_nan.rs
index cadbbd58af5..3ffdb6868ac 100644
--- a/src/tools/miri/tests/pass/float_nan.rs
+++ b/src/tools/miri/tests/pass/float_nan.rs
@@ -260,6 +260,7 @@ fn test_f32() {
 
     // Intrinsics
     let nan = F32::nan(Neg, Quiet, 0).as_f32();
+    let snan = F32::nan(Neg, Signaling, 1).as_f32();
     check_all_outcomes(
         HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
         || F32::from(f32::min(nan, nan)),
@@ -313,6 +314,18 @@ fn test_f32() {
         HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
         || F32::from(nan.ln_gamma().0),
     );
+    check_all_outcomes(
+        HashSet::from_iter([
+            F32::from(1.0),
+            F32::nan(Pos, Quiet, 0),
+            F32::nan(Neg, Quiet, 0),
+            F32::nan(Pos, Quiet, 1),
+            F32::nan(Neg, Quiet, 1),
+            F32::nan(Pos, Signaling, 1),
+            F32::nan(Neg, Signaling, 1),
+        ]),
+        || F32::from(snan.powf(0.0)),
+    );
 }
 
 fn test_f64() {
@@ -376,6 +389,7 @@ fn test_f64() {
 
     // Intrinsics
     let nan = F64::nan(Neg, Quiet, 0).as_f64();
+    let snan = F64::nan(Neg, Signaling, 1).as_f64();
     check_all_outcomes(
         HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
         || F64::from(f64::min(nan, nan)),
@@ -433,6 +447,18 @@ fn test_f64() {
         HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
         || F64::from(nan.ln_gamma().0),
     );
+    check_all_outcomes(
+        HashSet::from_iter([
+            F64::from(1.0),
+            F64::nan(Pos, Quiet, 0),
+            F64::nan(Neg, Quiet, 0),
+            F64::nan(Pos, Quiet, 1),
+            F64::nan(Neg, Quiet, 1),
+            F64::nan(Pos, Signaling, 1),
+            F64::nan(Neg, Signaling, 1),
+        ]),
+        || F64::from(snan.powf(0.0)),
+    );
 }
 
 fn test_casts() {
diff --git a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
index e14ce51f35a..726d4c01cc3 100644
--- a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
+++ b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
@@ -570,6 +570,10 @@ fn simd_round() {
         f32x4::from_array([1.0, 1.0, 2.0, -5.0])
     );
     assert_eq!(
+        unsafe { intrinsics::simd_round_ties_even(f32x4::from_array([0.9, 1.001, 2.0, -4.5])) },
+        f32x4::from_array([1.0, 1.0, 2.0, -4.0])
+    );
+    assert_eq!(
         f32x4::from_array([0.9, 1.001, 2.0, -4.5]).trunc(),
         f32x4::from_array([0.0, 1.0, 2.0, -4.0])
     );
@@ -587,6 +591,10 @@ fn simd_round() {
         f64x4::from_array([1.0, 1.0, 2.0, -5.0])
     );
     assert_eq!(
+        unsafe { intrinsics::simd_round_ties_even(f64x4::from_array([0.9, 1.001, 2.0, -4.5])) },
+        f64x4::from_array([1.0, 1.0, 2.0, -4.0])
+    );
+    assert_eq!(
         f64x4::from_array([0.9, 1.001, 2.0, -4.5]).trunc(),
         f64x4::from_array([0.0, 1.0, 2.0, -4.0])
     );
diff --git a/src/tools/miri/tests/pass/shims/time.rs b/src/tools/miri/tests/pass/shims/time.rs
index 226f04ade0f..ef0b400f1a7 100644
--- a/src/tools/miri/tests/pass/shims/time.rs
+++ b/src/tools/miri/tests/pass/shims/time.rs
@@ -1,4 +1,5 @@
 //@compile-flags: -Zmiri-disable-isolation
+#![feature(thread_sleep_until)]
 
 use std::time::{Duration, Instant, SystemTime};
 
@@ -15,6 +16,14 @@ fn test_sleep() {
     assert!((after - before).as_millis() >= 100);
 }
 
+fn test_sleep_until() {
+    let before = Instant::now();
+    let hunderd_millis_after_start = before + Duration::from_millis(100);
+    std::thread::sleep_until(hunderd_millis_after_start);
+    let after = Instant::now();
+    assert!((after - before).as_millis() >= 100);
+}
+
 fn main() {
     // Check `SystemTime`.
     let now1 = SystemTime::now();
@@ -49,4 +58,5 @@ fn main() {
     duration_sanity(diff);
 
     test_sleep();
+    test_sleep_until();
 }
diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs
index 46472b51f9c..5239f8338ee 100644
--- a/src/tools/miri/tests/ui.rs
+++ b/src/tools/miri/tests/ui.rs
@@ -29,20 +29,17 @@ fn miri_path() -> PathBuf {
     PathBuf::from(env::var("MIRI").unwrap_or_else(|_| env!("CARGO_BIN_EXE_miri").into()))
 }
 
-fn get_host() -> String {
-    rustc_version::VersionMeta::for_command(std::process::Command::new(miri_path()))
-        .expect("failed to parse rustc version info")
-        .host
-}
-
 pub fn flagsplit(flags: &str) -> Vec<String> {
     // This code is taken from `RUSTFLAGS` handling in cargo.
     flags.split(' ').map(str::trim).filter(|s| !s.is_empty()).map(str::to_string).collect()
 }
 
 // Build the shared object file for testing native function calls.
-fn build_native_lib() -> PathBuf {
-    let cc = env::var("CC").unwrap_or_else(|_| "cc".into());
+fn build_native_lib(target: &str) -> PathBuf {
+    // Loosely follow the logic of the `cc` crate for finding the compiler.
+    let cc = env::var(format!("CC_{target}"))
+        .or_else(|_| env::var("CC"))
+        .unwrap_or_else(|_| "cc".into());
     // Target directory that we can write to.
     let so_target_dir = Path::new(env!("CARGO_TARGET_TMPDIR")).join("miri-native-lib");
     // Create the directory if it does not already exist.
@@ -201,7 +198,7 @@ fn run_tests(
     // If we're testing the native-lib functionality, then build the shared object file for testing
     // external C function calls and push the relevant compiler flag.
     if path.starts_with("tests/native-lib/") {
-        let native_lib = build_native_lib();
+        let native_lib = build_native_lib(target);
         let mut flag = std::ffi::OsString::from("-Zmiri-native-lib=");
         flag.push(native_lib.into_os_string());
         config.program.args.push(flag);
@@ -305,14 +302,21 @@ fn ui(
         .with_context(|| format!("ui tests in {path} for {target} failed"))
 }
 
-fn get_target() -> String {
-    env::var("MIRI_TEST_TARGET").ok().unwrap_or_else(get_host)
+fn get_host() -> String {
+    rustc_version::VersionMeta::for_command(std::process::Command::new(miri_path()))
+        .expect("failed to parse rustc version info")
+        .host
+}
+
+fn get_target(host: &str) -> String {
+    env::var("MIRI_TEST_TARGET").ok().unwrap_or_else(|| host.to_owned())
 }
 
 fn main() -> Result<()> {
     ui_test::color_eyre::install()?;
 
-    let target = get_target();
+    let host = get_host();
+    let target = get_target(&host);
     let tmpdir = tempfile::Builder::new().prefix("miri-uitest-").tempdir()?;
 
     let mut args = std::env::args_os();
@@ -329,7 +333,7 @@ fn main() -> Result<()> {
     ui(Mode::Panic, "tests/panic", &target, WithDependencies, tmpdir.path())?;
     ui(Mode::Fail, "tests/fail", &target, WithoutDependencies, tmpdir.path())?;
     ui(Mode::Fail, "tests/fail-dep", &target, WithDependencies, tmpdir.path())?;
-    if cfg!(unix) {
+    if cfg!(unix) && target == host {
         ui(Mode::Pass, "tests/native-lib/pass", &target, WithoutDependencies, tmpdir.path())?;
         ui(Mode::Fail, "tests/native-lib/fail", &target, WithoutDependencies, tmpdir.path())?;
     }
diff --git a/src/tools/opt-dist/src/exec.rs b/src/tools/opt-dist/src/exec.rs
index 64ce5cc3775..0dc6e56b9d5 100644
--- a/src/tools/opt-dist/src/exec.rs
+++ b/src/tools/opt-dist/src/exec.rs
@@ -122,7 +122,12 @@ impl Bootstrap {
         let metrics_path = env.build_root().join("build").join("metrics.json");
         let args = dist_args.iter().map(|arg| arg.as_str()).collect::<Vec<_>>();
         let cmd = cmd(&args).env("RUST_BACKTRACE", "full");
-        let cmd = add_shared_x_flags(env, cmd);
+        let mut cmd = add_shared_x_flags(env, cmd);
+        if env.is_fast_try_build() {
+            // We set build.extended=false for fast try builds, but we still need Cargo
+            cmd = cmd.arg("cargo");
+        }
+
         Self { cmd, metrics_path }
     }
 
@@ -189,5 +194,18 @@ impl Bootstrap {
 }
 
 fn add_shared_x_flags(env: &Environment, cmd: CmdBuilder) -> CmdBuilder {
-    if env.is_fast_try_build() { cmd.arg("--set").arg("rust.deny-warnings=false") } else { cmd }
+    if env.is_fast_try_build() {
+        // Skip things that cannot be skipped through `x ... --skip`
+        cmd.arg("--set")
+            .arg("rust.llvm-bitcode-linker=false")
+            // Skip wasm-component-ld. This also skips cargo, which we need to re-enable for dist
+            .arg("--set")
+            .arg("build.extended=false")
+            .arg("--set")
+            .arg("rust.codegen-backends=['llvm']")
+            .arg("--set")
+            .arg("rust.deny-warnings=false")
+    } else {
+        cmd
+    }
 }
diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs
index d2827ec01ca..9c8a6637a3b 100644
--- a/src/tools/opt-dist/src/main.rs
+++ b/src/tools/opt-dist/src/main.rs
@@ -407,13 +407,18 @@ fn main() -> anyhow::Result<()> {
         for target in [
             "rust-docs",
             "rustc-docs",
+            "rustc-dev",
+            "rust-dev",
             "rust-docs-json",
             "rust-analyzer",
             "rustc-src",
+            "extended",
             "clippy",
             "miri",
             "rustfmt",
             "gcc",
+            "generate-copyright",
+            "bootstrap",
         ] {
             build_args.extend(["--skip".to_string(), target.to_string()]);
         }
diff --git a/src/tools/opt-dist/src/tests.rs b/src/tools/opt-dist/src/tests.rs
index 53ce772fa77..705a1750ae8 100644
--- a/src/tools/opt-dist/src/tests.rs
+++ b/src/tools/opt-dist/src/tests.rs
@@ -72,6 +72,8 @@ change-id = 115898
 [rust]
 channel = "{channel}"
 verbose-tests = true
+# rust-lld cannot be combined with an external LLVM
+lld = false
 
 [build]
 rustc = "{rustc}"
diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml
index 15ed03ad5c2..3226f467ba4 100644
--- a/src/tools/run-make-support/Cargo.toml
+++ b/src/tools/run-make-support/Cargo.toml
@@ -4,12 +4,12 @@ version = "0.2.0"
 edition = "2021"
 
 [dependencies]
-bstr = "1.6.0"
-object = "0.36.2"
-similar = "2.5.0"
+bstr = "1.12"
+object = "0.37"
+similar = "2.7"
 wasmparser = { version = "0.219", default-features = false, features = ["std"] }
-regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace
-gimli = "0.31.0"
+regex = "1.11"
+gimli = "0.32"
 build_helper = { path = "../../build_helper" }
 serde_json = "1.0"
 libc = "0.2"
diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml
index 79fb7a2d2ea..770652494f4 100644
--- a/src/tools/rust-analyzer/.github/workflows/ci.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml
@@ -17,6 +17,10 @@ env:
   RUST_BACKTRACE: short
   RUSTUP_MAX_RETRIES: 10
 
+defaults:
+  run:
+    shell: bash
+
 jobs:
   changes:
     runs-on: ubuntu-latest
@@ -80,6 +84,7 @@ jobs:
       CC: deny_c
 
     strategy:
+      fail-fast: false
       matrix:
         os: [ubuntu-latest, windows-latest, macos-latest]
 
@@ -99,7 +104,7 @@ jobs:
           rustup toolchain install nightly --profile minimal --component rustfmt
       # https://github.com/actions-rust-lang/setup-rust-toolchain/blob/main/rust.json
       - name: Install Rust Problem Matcher
-        if: matrix.os == 'ubuntu-latest'
+        if: matrix.os == 'macos-latest'
         run: echo "::add-matcher::.github/rust.json"
 
       # - name: Cache Dependencies
@@ -116,23 +121,9 @@ jobs:
         if: matrix.os == 'ubuntu-latest'
         run: cargo codegen --check
 
-      - name: Compile tests
-        run: cargo test --no-run
-
       - name: Run tests
         run: cargo nextest run --no-fail-fast --hide-progress-bar --status-level fail
 
-      - name: Cancel parallel jobs
-        if: failure()
-        run: |
-          # https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#cancel-a-workflow-run
-          curl -L \
-          -X POST \
-          -H "Accept: application/vnd.github.v3+json" \
-          -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
-          -H "X-GitHub-Api-Version: 2022-11-28" \
-          https://api.github.com/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/cancel
-
       - name: Run Clippy
         if: matrix.os == 'macos-latest'
         run: cargo clippy --all-targets -- -D clippy::disallowed_macros -D clippy::dbg_macro -D clippy::todo -D clippy::print_stdout -D clippy::print_stderr
@@ -333,3 +324,21 @@ jobs:
           jq -C <<< '${{ toJson(needs) }}'
           # Check if all jobs that we depend on (in the needs array) were successful (or have been skipped).
           jq --exit-status 'all(.result == "success" or .result == "skipped")' <<< '${{ toJson(needs) }}'
+
+  cancel-if-matrix-failed:
+    needs: rust
+    if: ${{ always() }}
+    runs-on: ubuntu-latest
+    steps:
+      - name: Cancel parallel jobs
+        run: |
+          if jq --exit-status 'all(.result == "success" or .result == "skipped")' <<< '${{ toJson(needs) }}'; then
+            exit 0
+          fi
+          # https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#cancel-a-workflow-run
+          curl -L \
+          -X POST \
+          -H "Accept: application/vnd.github.v3+json" \
+          -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
+          -H "X-GitHub-Api-Version: 2022-11-28" \
+          https://api.github.com/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/cancel
diff --git a/src/tools/rust-analyzer/.github/workflows/release.yaml b/src/tools/rust-analyzer/.github/workflows/release.yaml
index a758ecfd467..5bd90130f4c 100644
--- a/src/tools/rust-analyzer/.github/workflows/release.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/release.yaml
@@ -134,13 +134,13 @@ jobs:
 
       - name: Run analysis-stats on rust-analyzer
         if: matrix.target == 'x86_64-unknown-linux-gnu'
-        run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats .
+        run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats . -q
 
       - name: Run analysis-stats on rust std library
         if: matrix.target == 'x86_64-unknown-linux-gnu'
         env:
           RUSTC_BOOTSTRAP: 1
-        run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std
+        run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std -q
 
       - name: Upload artifacts
         uses: actions/upload-artifact@v4
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 2c7b4641641..7432a82080d 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -570,12 +570,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "heck"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
-
-[[package]]
 name = "hermit-abi"
 version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1021,6 +1015,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "intrusive-collections"
+version = "0.9.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "189d0897e4cbe8c75efedf3502c18c887b05046e59d28404d4d8e46cbc4d1e86"
+dependencies = [
+ "memoffset",
+]
+
+[[package]]
 name = "itertools"
 version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1428,6 +1431,16 @@ dependencies = [
 ]
 
 [[package]]
+name = "papaya"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f92dd0b07c53a0a0c764db2ace8c541dc47320dad97c2200c2a637ab9dd2328f"
+dependencies = [
+ "equivalent",
+ "seize",
+]
+
+[[package]]
 name = "parking_lot"
 version = "0.12.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1458,7 +1471,7 @@ dependencies = [
  "edition",
  "expect-test",
  "ra-ap-rustc_lexer",
- "rustc-literal-escaper 0.0.3",
+ "rustc-literal-escaper 0.0.4",
  "stdx",
  "tracing",
 ]
@@ -1927,9 +1940,9 @@ checksum = "0041b6238913c41fe704213a4a9329e2f685a156d1781998128b4149c230ad04"
 
 [[package]]
 name = "rustc-literal-escaper"
-version = "0.0.3"
+version = "0.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78744cd17f5d01c75b709e49807d1363e02a940ccee2e9e72435843fdb0d076e"
+checksum = "ab03008eb631b703dd16978282ae36c73282e7922fe101a4bd072a40ecea7b8b"
 
 [[package]]
 name = "rustc-stable-hash"
@@ -1955,16 +1968,18 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
 
 [[package]]
 name = "salsa"
-version = "0.22.0"
+version = "0.23.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8fff508e3d6ef42a32607f7538e17171a877a12015e32036f46e99d00c95781"
+checksum = "2e235afdb8e510f38a07138fbe5a0b64691894358a9c0cbd813b1aade110efc9"
 dependencies = [
  "boxcar",
  "crossbeam-queue",
- "dashmap",
+ "crossbeam-utils",
  "hashbrown 0.15.4",
  "hashlink",
  "indexmap",
+ "intrusive-collections",
+ "papaya",
  "parking_lot",
  "portable-atomic",
  "rayon",
@@ -1978,17 +1993,16 @@ dependencies = [
 
 [[package]]
 name = "salsa-macro-rules"
-version = "0.22.0"
+version = "0.23.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ea72b3c06f2ce6350fe3a0eeb7aaaf842d1d8352b706973c19c4f02e298a87c"
+checksum = "2edb86a7e9c91f6d30c9ce054312721dbe773a162db27bbfae834d16177b30ce"
 
 [[package]]
 name = "salsa-macros"
-version = "0.22.0"
+version = "0.23.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ce92025bc160b27814a207cb78d680973af17f863c7f4fc56cf3a535e22f378"
+checksum = "d0778d6e209051bc4e75acfe83bcd7848601ec3dbe9c3dbb982829020e9128af"
 dependencies = [
- "heck",
  "proc-macro2",
  "quote",
  "syn",
@@ -2026,6 +2040,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
 [[package]]
+name = "seize"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e4b8d813387d566f627f3ea1b914c068aac94c40ae27ec43f5f33bde65abefe7"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
 name = "semver"
 version = "1.0.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2207,7 +2231,7 @@ dependencies = [
  "rayon",
  "rowan",
  "rustc-hash 2.1.1",
- "rustc-literal-escaper 0.0.3",
+ "rustc-literal-escaper 0.0.4",
  "rustc_apfloat",
  "smol_str",
  "stdx",
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 449c75859cf..d268ce5b0bb 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -49,6 +49,8 @@ debug = 2
 # ungrammar = { path = "../ungrammar" }
 
 # salsa = { path = "../salsa" }
+# salsa-macros = { path = "../salsa/components/salsa-macros" }
+# salsa-macro-rules = { path = "../salsa/components/salsa-macro-rules" }
 
 [workspace.dependencies]
 # local crates
@@ -136,14 +138,14 @@ rayon = "1.10.0"
 rowan = "=0.15.15"
 # Ideally we'd not enable the macros feature but unfortunately the `tracked` attribute does not work
 # on impls without it
-salsa = { version = "0.22.0", default-features = true, features = ["rayon","salsa_unstable", "macros"] }
-salsa-macros = "0.22.0"
+salsa = { version = "0.23.0", default-features = true, features = ["rayon","salsa_unstable", "macros"] }
+salsa-macros = "0.23.0"
 semver = "1.0.26"
 serde = { version = "1.0.219" }
 serde_derive = { version = "1.0.219" }
 serde_json = "1.0.140"
 rustc-hash = "2.1.1"
-rustc-literal-escaper = "0.0.3"
+rustc-literal-escaper = "0.0.4"
 smallvec = { version = "1.15.1", features = [
   "const_new",
   "union",
diff --git a/src/tools/rust-analyzer/crates/base-db/Cargo.toml b/src/tools/rust-analyzer/crates/base-db/Cargo.toml
index 3b423a86f97..ea06fd9c48f 100644
--- a/src/tools/rust-analyzer/crates/base-db/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/base-db/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 la-arena.workspace = true
diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs
index 2a87b152487..8c9393bcc93 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/input.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs
@@ -6,6 +6,7 @@
 //! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how
 //! actual IO is done and lowered to input.
 
+use std::error::Error;
 use std::hash::BuildHasherDefault;
 use std::{fmt, mem, ops};
 
@@ -22,7 +23,49 @@ use vfs::{AbsPathBuf, AnchoredPath, FileId, VfsPath, file_set::FileSet};
 
 use crate::{CrateWorkspaceData, EditionedFileId, FxIndexSet, RootQueryDb};
 
-pub type ProcMacroPaths = FxHashMap<CrateBuilderId, Result<(String, AbsPathBuf), String>>;
+pub type ProcMacroPaths =
+    FxHashMap<CrateBuilderId, Result<(String, AbsPathBuf), ProcMacroLoadingError>>;
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum ProcMacroLoadingError {
+    Disabled,
+    FailedToBuild,
+    MissingDylibPath,
+    NotYetBuilt,
+    NoProcMacros,
+    ProcMacroSrvError(Box<str>),
+}
+impl ProcMacroLoadingError {
+    pub fn is_hard_error(&self) -> bool {
+        match self {
+            ProcMacroLoadingError::Disabled | ProcMacroLoadingError::NotYetBuilt => false,
+            ProcMacroLoadingError::FailedToBuild
+            | ProcMacroLoadingError::MissingDylibPath
+            | ProcMacroLoadingError::NoProcMacros
+            | ProcMacroLoadingError::ProcMacroSrvError(_) => true,
+        }
+    }
+}
+
+impl Error for ProcMacroLoadingError {}
+impl fmt::Display for ProcMacroLoadingError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            ProcMacroLoadingError::Disabled => write!(f, "proc-macro expansion is disabled"),
+            ProcMacroLoadingError::FailedToBuild => write!(f, "proc-macro failed to build"),
+            ProcMacroLoadingError::MissingDylibPath => {
+                write!(f, "proc-macro crate build data is missing a dylib path")
+            }
+            ProcMacroLoadingError::NotYetBuilt => write!(f, "proc-macro not yet built"),
+            ProcMacroLoadingError::NoProcMacros => {
+                write!(f, "proc macro library has no proc macros")
+            }
+            ProcMacroLoadingError::ProcMacroSrvError(msg) => {
+                write!(f, "proc macro server error: {msg}")
+            }
+        }
+    }
+}
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
 pub struct SourceRootId(pub u32);
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 478fae67c80..ad17f1730be 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
@@ -14,8 +14,9 @@ pub use crate::{
     input::{
         BuiltCrateData, BuiltDependency, Crate, CrateBuilder, CrateBuilderId, CrateDataBuilder,
         CrateDisplayName, CrateGraphBuilder, CrateName, CrateOrigin, CratesIdMap, CratesMap,
-        DependencyBuilder, Env, ExtraCrateData, LangCrateOrigin, ProcMacroPaths, ReleaseChannel,
-        SourceRoot, SourceRootId, TargetLayoutLoadResult, UniqueCrateData,
+        DependencyBuilder, Env, ExtraCrateData, LangCrateOrigin, ProcMacroLoadingError,
+        ProcMacroPaths, ReleaseChannel, SourceRoot, SourceRootId, TargetLayoutLoadResult,
+        UniqueCrateData,
     },
 };
 use dashmap::{DashMap, mapref::entry::Entry};
@@ -33,7 +34,7 @@ pub type FxIndexSet<T> = indexmap::IndexSet<T, rustc_hash::FxBuildHasher>;
 #[macro_export]
 macro_rules! impl_intern_key {
     ($id:ident, $loc:ident) => {
-        #[salsa_macros::interned(no_lifetime)]
+        #[salsa_macros::interned(no_lifetime, revisions = usize::MAX)]
         #[derive(PartialOrd, Ord)]
         pub struct $id {
             pub loc: $loc,
@@ -43,7 +44,7 @@ macro_rules! impl_intern_key {
         impl ::std::fmt::Debug for $id {
             fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
                 f.debug_tuple(stringify!($id))
-                    .field(&format_args!("{:04x}", self.0.as_u32()))
+                    .field(&format_args!("{:04x}", self.0.index()))
                     .finish()
             }
         }
@@ -167,7 +168,7 @@ impl Files {
     }
 }
 
-#[salsa_macros::interned(no_lifetime, debug, constructor=from_span)]
+#[salsa_macros::interned(no_lifetime, debug, constructor=from_span, revisions = usize::MAX)]
 #[derive(PartialOrd, Ord)]
 pub struct EditionedFileId {
     pub editioned_file_id: span::EditionedFileId,
diff --git a/src/tools/rust-analyzer/crates/cfg/Cargo.toml b/src/tools/rust-analyzer/crates/cfg/Cargo.toml
index d7764a16c04..ba349666145 100644
--- a/src/tools/rust-analyzer/crates/cfg/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/cfg/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 rustc-hash.workspace = true
diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
index c6922eca49f..abb4819a767 100644
--- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 arrayvec.workspace = true
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
index 00408e95ae6..c67bb2422ac 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
@@ -25,11 +25,10 @@ use crate::{
     import_map::ImportMap,
     item_tree::{ItemTree, file_item_tree_query},
     lang_item::{self, LangItem},
-    nameres::{assoc::TraitItems, crate_def_map, diagnostics::DefDiagnostics},
+    nameres::crate_def_map,
     signatures::{
         ConstSignature, EnumSignature, FunctionSignature, ImplSignature, StaticSignature,
         StructSignature, TraitAliasSignature, TraitSignature, TypeAliasSignature, UnionSignature,
-        VariantFields,
     },
     tt,
     visibility::{self, Visibility},
@@ -113,24 +112,6 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase {
 
     // region:data
 
-    #[salsa::invoke(VariantFields::query)]
-    fn variant_fields_with_source_map(
-        &self,
-        id: VariantId,
-    ) -> (Arc<VariantFields>, Arc<ExpressionStoreSourceMap>);
-
-    #[salsa::transparent]
-    #[salsa::invoke(TraitItems::trait_items_query)]
-    fn trait_items(&self, e: TraitId) -> Arc<TraitItems>;
-
-    #[salsa::invoke(TraitItems::trait_items_with_diagnostics_query)]
-    fn trait_items_with_diagnostics(&self, tr: TraitId) -> (Arc<TraitItems>, DefDiagnostics);
-
-    #[salsa::tracked]
-    fn variant_fields(&self, id: VariantId) -> Arc<VariantFields> {
-        self.variant_fields_with_source_map(id).0
-    }
-
     #[salsa::tracked]
     fn trait_signature(&self, trait_: TraitId) -> Arc<TraitSignature> {
         self.trait_signature_with_source_map(trait_).0
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
index f617c3225ae..51612f341a1 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
@@ -9,7 +9,10 @@ pub mod scope;
 #[cfg(test)]
 mod tests;
 
-use std::ops::{Deref, Index};
+use std::{
+    ops::{Deref, Index},
+    sync::LazyLock,
+};
 
 use cfg::{CfgExpr, CfgOptions};
 use either::Either;
@@ -19,6 +22,7 @@ use rustc_hash::FxHashMap;
 use smallvec::SmallVec;
 use span::{Edition, SyntaxContext};
 use syntax::{AstPtr, SyntaxNodePtr, ast};
+use triomphe::Arc;
 use tt::TextRange;
 
 use crate::{
@@ -89,7 +93,7 @@ pub type TypeSource = InFile<TypePtr>;
 pub type LifetimePtr = AstPtr<ast::Lifetime>;
 pub type LifetimeSource = InFile<LifetimePtr>;
 
-#[derive(Debug, Eq, PartialEq)]
+#[derive(Debug, PartialEq, Eq)]
 pub struct ExpressionStore {
     pub exprs: Arena<Expr>,
     pub pats: Arena<Pat>,
@@ -110,7 +114,7 @@ pub struct ExpressionStore {
     ident_hygiene: FxHashMap<ExprOrPatId, HygieneId>,
 }
 
-#[derive(Debug, Eq, PartialEq, Default)]
+#[derive(Debug, Eq, Default)]
 pub struct ExpressionStoreSourceMap {
     // AST expressions can create patterns in destructuring assignments. Therefore, `ExprSource` can also map
     // to `PatId`, and `PatId` can also map to `ExprSource` (the other way around is unaffected).
@@ -123,19 +127,20 @@ pub struct ExpressionStoreSourceMap {
     label_map: FxHashMap<LabelSource, LabelId>,
     label_map_back: ArenaMap<LabelId, LabelSource>,
 
-    binding_definitions: FxHashMap<BindingId, SmallVec<[PatId; 4]>>,
-
-    /// We don't create explicit nodes for record fields (`S { record_field: 92 }`).
-    /// Instead, we use id of expression (`92`) to identify the field.
-    field_map_back: FxHashMap<ExprId, FieldSource>,
-    pat_field_map_back: FxHashMap<PatId, PatFieldSource>,
-
     types_map_back: ArenaMap<TypeRefId, TypeSource>,
     types_map: FxHashMap<TypeSource, TypeRefId>,
 
     lifetime_map_back: ArenaMap<LifetimeRefId, LifetimeSource>,
     lifetime_map: FxHashMap<LifetimeSource, LifetimeRefId>,
 
+    binding_definitions:
+        ArenaMap<BindingId, SmallVec<[PatId; 2 * size_of::<usize>() / size_of::<PatId>()]>>,
+
+    /// We don't create explicit nodes for record fields (`S { record_field: 92 }`).
+    /// Instead, we use id of expression (`92`) to identify the field.
+    field_map_back: FxHashMap<ExprId, FieldSource>,
+    pat_field_map_back: FxHashMap<PatId, PatFieldSource>,
+
     template_map: Option<Box<FormatTemplate>>,
 
     pub expansions: FxHashMap<InFile<MacroCallPtr>, MacroCallId>,
@@ -145,6 +150,43 @@ pub struct ExpressionStoreSourceMap {
     pub diagnostics: Vec<ExpressionStoreDiagnostics>,
 }
 
+impl PartialEq for ExpressionStoreSourceMap {
+    fn eq(&self, other: &Self) -> bool {
+        // we only need to compare one of the two mappings
+        // as the other is a reverse mapping and thus will compare
+        // the same as normal mapping
+        let Self {
+            expr_map: _,
+            expr_map_back,
+            pat_map: _,
+            pat_map_back,
+            label_map: _,
+            label_map_back,
+            types_map_back,
+            types_map: _,
+            lifetime_map_back,
+            lifetime_map: _,
+            // If this changed, our pattern data must have changed
+            binding_definitions: _,
+            // If this changed, our expression data must have changed
+            field_map_back: _,
+            // If this changed, our pattern data must have changed
+            pat_field_map_back: _,
+            template_map,
+            expansions,
+            diagnostics,
+        } = self;
+        *expr_map_back == other.expr_map_back
+            && *pat_map_back == other.pat_map_back
+            && *label_map_back == other.label_map_back
+            && *types_map_back == other.types_map_back
+            && *lifetime_map_back == other.lifetime_map_back
+            && *template_map == other.template_map
+            && *expansions == other.expansions
+            && *diagnostics == other.diagnostics
+    }
+}
+
 /// The body of an item (function, const etc.).
 #[derive(Debug, Eq, PartialEq, Default)]
 pub struct ExpressionStoreBuilder {
@@ -220,6 +262,12 @@ impl ExpressionStoreBuilder {
 }
 
 impl ExpressionStore {
+    pub fn empty_singleton() -> Arc<Self> {
+        static EMPTY: LazyLock<Arc<ExpressionStore>> =
+            LazyLock::new(|| Arc::new(ExpressionStoreBuilder::default().finish()));
+        EMPTY.clone()
+    }
+
     /// Returns an iterator over all block expressions in this store that define inner items.
     pub fn blocks<'a>(
         &'a self,
@@ -636,6 +684,12 @@ impl Index<PathId> for ExpressionStore {
 // FIXME: Change `node_` prefix to something more reasonable.
 // Perhaps `expr_syntax` and `expr_id`?
 impl ExpressionStoreSourceMap {
+    pub fn empty_singleton() -> Arc<Self> {
+        static EMPTY: LazyLock<Arc<ExpressionStoreSourceMap>> =
+            LazyLock::new(|| Arc::new(ExpressionStoreSourceMap::default()));
+        EMPTY.clone()
+    }
+
     pub fn expr_or_pat_syntax(&self, id: ExprOrPatId) -> Result<ExprOrPatSource, SyntheticSyntax> {
         match id {
             ExprOrPatId::ExprId(id) => self.expr_syntax(id),
@@ -682,7 +736,7 @@ impl ExpressionStoreSourceMap {
     }
 
     pub fn patterns_for_binding(&self, binding: BindingId) -> &[PatId] {
-        self.binding_definitions.get(&binding).map_or(&[], Deref::deref)
+        self.binding_definitions.get(binding).map_or(&[], Deref::deref)
     }
 
     pub fn node_label(&self, node: InFile<&ast::Label>) -> Option<LabelId> {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
index efa1374a446..c0e51b338b4 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
@@ -2250,7 +2250,7 @@ impl ExprCollector<'_> {
                         Some(ModuleDefId::ConstId(_)) => (None, Pat::Path(name.into())),
                         Some(ModuleDefId::EnumVariantId(variant))
                         // FIXME: This can cause a cycle if the user is writing invalid code
-                            if self.db.variant_fields(variant.into()).shape != FieldsShape::Record =>
+                            if variant.fields(self.db).shape != FieldsShape::Record =>
                         {
                             (None, Pat::Path(name.into()))
                         }
@@ -2825,14 +2825,7 @@ impl ExprCollector<'_> {
         let use_format_args_since_1_89_0 = fmt_args().is_some() && fmt_unsafe_arg().is_none();
 
         let idx = if use_format_args_since_1_89_0 {
-            self.collect_format_args_impl(
-                syntax_ptr,
-                fmt,
-                hygiene,
-                argmap,
-                lit_pieces,
-                format_options,
-            )
+            self.collect_format_args_impl(syntax_ptr, fmt, argmap, lit_pieces, format_options)
         } else {
             self.collect_format_args_before_1_89_0_impl(
                 syntax_ptr,
@@ -2962,7 +2955,6 @@ impl ExprCollector<'_> {
         &mut self,
         syntax_ptr: AstPtr<ast::Expr>,
         fmt: FormatArgs,
-        hygiene: HygieneId,
         argmap: FxIndexSet<(usize, ArgumentType)>,
         lit_pieces: ExprId,
         format_options: ExprId,
@@ -2997,8 +2989,11 @@ impl ExprCollector<'_> {
             let args =
                 self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
             let args_name = Name::new_symbol_root(sym::args);
-            let args_binding =
-                self.alloc_binding(args_name.clone(), BindingAnnotation::Unannotated, hygiene);
+            let args_binding = self.alloc_binding(
+                args_name.clone(),
+                BindingAnnotation::Unannotated,
+                HygieneId::ROOT,
+            );
             let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
             self.add_definition_to_binding(args_binding, args_pat);
             // TODO: We don't have `super let` yet.
@@ -3008,13 +3003,16 @@ impl ExprCollector<'_> {
                 initializer: Some(args),
                 else_branch: None,
             };
-            (vec![let_stmt], self.alloc_expr_desugared(Expr::Path(Path::from(args_name))))
+            (vec![let_stmt], self.alloc_expr_desugared(Expr::Path(args_name.into())))
         } else {
             // Generate:
             //     super let args = (&arg0, &arg1, &...);
             let args_name = Name::new_symbol_root(sym::args);
-            let args_binding =
-                self.alloc_binding(args_name.clone(), BindingAnnotation::Unannotated, hygiene);
+            let args_binding = self.alloc_binding(
+                args_name.clone(),
+                BindingAnnotation::Unannotated,
+                HygieneId::ROOT,
+            );
             let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
             self.add_definition_to_binding(args_binding, args_pat);
             let elements = arguments
@@ -3057,8 +3055,11 @@ impl ExprCollector<'_> {
                 .collect();
             let array =
                 self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
-            let args_binding =
-                self.alloc_binding(args_name.clone(), BindingAnnotation::Unannotated, hygiene);
+            let args_binding = self.alloc_binding(
+                args_name.clone(),
+                BindingAnnotation::Unannotated,
+                HygieneId::ROOT,
+            );
             let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
             self.add_definition_to_binding(args_binding, args_pat);
             let let_stmt2 = Statement::Let {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/path.rs
index db83e73a0b9..19c7ce0ce04 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/path.rs
@@ -29,8 +29,8 @@ pub enum Path {
 // This type is being used a lot, make sure it doesn't grow unintentionally.
 #[cfg(target_arch = "x86_64")]
 const _: () = {
-    assert!(size_of::<Path>() == 16);
-    assert!(size_of::<Option<Path>>() == 16);
+    assert!(size_of::<Path>() == 24);
+    assert!(size_of::<Option<Path>>() == 24);
 };
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs
index 56c7655f9ea..87bcd33ed7b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs
@@ -121,7 +121,7 @@ pub fn print_variant_body_hir(db: &dyn DefDatabase, owner: VariantId, edition: E
         VariantId::UnionId(it) => format!("union {}", item_name(db, it, "<missing>")),
     };
 
-    let fields = db.variant_fields(owner);
+    let fields = owner.fields(db);
 
     let mut p = Printer {
         db,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs
index a46711c67e8..2dd0b9bdb86 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs
@@ -535,7 +535,7 @@ fn foo() {
 
         let resolved = scopes.resolve_name_in_scope(expr_scope, &name_ref.as_name()).unwrap();
         let pat_src = source_map
-            .pat_syntax(*source_map.binding_definitions[&resolved.binding()].first().unwrap())
+            .pat_syntax(*source_map.binding_definitions[resolved.binding()].first().unwrap())
             .unwrap();
 
         let local_name = pat_src.value.syntax_node_ptr().to_node(file.syntax());
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs
index a9a0e36312c..94e683cb0f8 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs
@@ -331,13 +331,13 @@ impl GenericParams {
     }
 
     #[inline]
-    pub fn no_predicates(&self) -> bool {
+    pub fn has_no_predicates(&self) -> bool {
         self.where_predicates.is_empty()
     }
 
     #[inline]
-    pub fn where_predicates(&self) -> std::slice::Iter<'_, WherePredicate> {
-        self.where_predicates.iter()
+    pub fn where_predicates(&self) -> &[WherePredicate] {
+        &self.where_predicates
     }
 
     /// Iterator of type_or_consts field
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
index eb3b92d31f1..eacc3f3cedf 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
@@ -149,7 +149,7 @@ pub enum TypeRef {
 }
 
 #[cfg(target_arch = "x86_64")]
-const _: () = assert!(size_of::<TypeRef>() == 16);
+const _: () = assert!(size_of::<TypeRef>() == 24);
 
 pub type TypeRefId = Idx<TypeRef>;
 
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 a6138fb6821..f31f355cfa5 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
@@ -16,7 +16,7 @@ use crate::{
     AssocItemId, AttrDefId, Complete, FxIndexMap, ModuleDefId, ModuleId, TraitId,
     db::DefDatabase,
     item_scope::{ImportOrExternCrate, ItemInNs},
-    nameres::{DefMap, crate_def_map},
+    nameres::{DefMap, assoc::TraitItems, crate_def_map},
     visibility::Visibility,
 };
 
@@ -221,7 +221,7 @@ impl ImportMap {
         trait_import_info: &ImportInfo,
     ) {
         let _p = tracing::info_span!("collect_trait_assoc_items").entered();
-        for &(ref assoc_item_name, item) in &db.trait_items(tr).items {
+        for &(ref assoc_item_name, item) in &TraitItems::query(db, tr).items {
             let module_def_id = match item {
                 AssocItemId::FunctionId(f) => ModuleDefId::from(f),
                 AssocItemId::ConstId(c) => ModuleDefId::from(c),
@@ -482,7 +482,7 @@ mod tests {
     use expect_test::{Expect, expect};
     use test_fixture::WithFixture;
 
-    use crate::{ItemContainerId, Lookup, test_db::TestDB};
+    use crate::{ItemContainerId, Lookup, nameres::assoc::TraitItems, test_db::TestDB};
 
     use super::*;
 
@@ -580,7 +580,7 @@ mod tests {
 
         let trait_info = dependency_imports.import_info_for(ItemInNs::Types(trait_id.into()))?;
 
-        let trait_items = db.trait_items(trait_id);
+        let trait_items = TraitItems::query(db, trait_id);
         let (assoc_item_name, _) = trait_items
             .items
             .iter()
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 faff7d036a2..750308026ee 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
@@ -9,8 +9,10 @@ use triomphe::Arc;
 
 use crate::{
     AdtId, AssocItemId, AttrDefId, Crate, EnumId, EnumVariantId, FunctionId, ImplId, ModuleDefId,
-    StaticId, StructId, TraitId, TypeAliasId, UnionId, db::DefDatabase, expr_store::path::Path,
-    nameres::crate_def_map,
+    StaticId, StructId, TraitId, TypeAliasId, UnionId,
+    db::DefDatabase,
+    expr_store::path::Path,
+    nameres::{assoc::TraitItems, crate_def_map},
 };
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -113,14 +115,16 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option<Box<LangIt
             match def {
                 ModuleDefId::TraitId(trait_) => {
                     lang_items.collect_lang_item(db, trait_, LangItemTarget::Trait);
-                    db.trait_items(trait_).items.iter().for_each(|&(_, assoc_id)| match assoc_id {
-                        AssocItemId::FunctionId(f) => {
-                            lang_items.collect_lang_item(db, f, LangItemTarget::Function);
+                    TraitItems::query(db, trait_).items.iter().for_each(|&(_, assoc_id)| {
+                        match assoc_id {
+                            AssocItemId::FunctionId(f) => {
+                                lang_items.collect_lang_item(db, f, LangItemTarget::Function);
+                            }
+                            AssocItemId::TypeAliasId(alias) => {
+                                lang_items.collect_lang_item(db, alias, LangItemTarget::TypeAlias)
+                            }
+                            AssocItemId::ConstId(_) => {}
                         }
-                        AssocItemId::TypeAliasId(alias) => {
-                            lang_items.collect_lang_item(db, alias, LangItemTarget::TypeAlias)
-                        }
-                        AssocItemId::ConstId(_) => {}
                     });
                 }
                 ModuleDefId::AdtId(AdtId::EnumId(e)) => {
@@ -304,6 +308,8 @@ impl LangItem {
 language_item_table! {
 //  Variant name,            Name,                     Getter method name,         Target                  Generic requirements;
     Sized,                   sym::sized,               sized_trait,                Target::Trait,          GenericRequirement::Exact(0);
+    MetaSized,               sym::meta_sized,          sized_trait,                Target::Trait,          GenericRequirement::Exact(0);
+    PointeeSized,            sym::pointee_sized,       sized_trait,                Target::Trait,          GenericRequirement::Exact(0);
     Unsize,                  sym::unsize,              unsize_trait,               Target::Trait,          GenericRequirement::Minimum(1);
     /// Trait injected by `#[derive(PartialEq)]`, (i.e. "Partial EQ").
     StructuralPeq,           sym::structural_peq,      structural_peq_trait,       Target::Trait,          GenericRequirement::None;
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 a562f2d0af2..bdf8b453e2d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -87,9 +87,12 @@ use crate::{
     attr::Attrs,
     builtin_type::BuiltinType,
     db::DefDatabase,
+    expr_store::ExpressionStoreSourceMap,
     hir::generics::{LocalLifetimeParamId, LocalTypeOrConstParamId},
     nameres::{
-        LocalDefMap, assoc::ImplItems, block_def_map, crate_def_map, crate_local_def_map,
+        LocalDefMap,
+        assoc::{ImplItems, TraitItems},
+        block_def_map, crate_def_map, crate_local_def_map,
         diagnostics::DefDiagnostics,
     },
     signatures::{EnumVariants, InactiveEnumVariantCode, VariantFields},
@@ -252,9 +255,35 @@ impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function);
 type StructLoc = ItemLoc<ast::Struct>;
 impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct);
 
+impl StructId {
+    pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields {
+        VariantFields::firewall(db, self.into())
+    }
+
+    pub fn fields_with_source_map(
+        self,
+        db: &dyn DefDatabase,
+    ) -> (Arc<VariantFields>, Arc<ExpressionStoreSourceMap>) {
+        VariantFields::query(db, self.into())
+    }
+}
+
 pub type UnionLoc = ItemLoc<ast::Union>;
 impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union);
 
+impl UnionId {
+    pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields {
+        VariantFields::firewall(db, self.into())
+    }
+
+    pub fn fields_with_source_map(
+        self,
+        db: &dyn DefDatabase,
+    ) -> (Arc<VariantFields>, Arc<ExpressionStoreSourceMap>) {
+        VariantFields::query(db, self.into())
+    }
+}
+
 pub type EnumLoc = ItemLoc<ast::Enum>;
 impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum);
 
@@ -282,6 +311,13 @@ impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static);
 pub type TraitLoc = ItemLoc<ast::Trait>;
 impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait);
 
+impl TraitId {
+    #[inline]
+    pub fn trait_items(self, db: &dyn DefDatabase) -> &TraitItems {
+        TraitItems::query(db, self)
+    }
+}
+
 pub type TraitAliasLoc = ItemLoc<ast::TraitAlias>;
 impl_intern!(TraitAliasId, TraitAliasLoc, intern_trait_alias, lookup_intern_trait_alias);
 
@@ -328,6 +364,20 @@ pub struct EnumVariantLoc {
 }
 impl_intern!(EnumVariantId, EnumVariantLoc, intern_enum_variant, lookup_intern_enum_variant);
 impl_loc!(EnumVariantLoc, id: Variant, parent: EnumId);
+
+impl EnumVariantId {
+    pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields {
+        VariantFields::firewall(db, self.into())
+    }
+
+    pub fn fields_with_source_map(
+        self,
+        db: &dyn DefDatabase,
+    ) -> (Arc<VariantFields>, Arc<ExpressionStoreSourceMap>) {
+        VariantFields::query(db, self.into())
+    }
+}
+
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct Macro2Loc {
     pub container: ModuleId,
@@ -1015,8 +1065,15 @@ pub enum VariantId {
 impl_from!(EnumVariantId, StructId, UnionId for VariantId);
 
 impl VariantId {
-    pub fn variant_data(self, db: &dyn DefDatabase) -> Arc<VariantFields> {
-        db.variant_fields(self)
+    pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields {
+        VariantFields::firewall(db, self)
+    }
+
+    pub fn fields_with_source_map(
+        self,
+        db: &dyn DefDatabase,
+    ) -> (Arc<VariantFields>, Arc<ExpressionStoreSourceMap>) {
+        VariantFields::query(db, self)
     }
 
     pub fn file_id(self, db: &dyn DefDatabase) -> HirFileId {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs
index 777953d3f21..0013c2a2567 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs
@@ -746,3 +746,83 @@ struct Struct9<#[pointee] T, U>(T) where T: ?Sized;
             623..690: `derive(CoercePointee)` requires `T` to be marked `?Sized`"#]],
     );
 }
+
+#[test]
+fn union_derive() {
+    check_errors(
+        r#"
+//- minicore: clone, copy, default, fmt, hash, ord, eq, derive
+
+#[derive(Copy)]
+union Foo1 { _v: () }
+#[derive(Clone)]
+union Foo2 { _v: () }
+#[derive(Default)]
+union Foo3 { _v: () }
+#[derive(Debug)]
+union Foo4 { _v: () }
+#[derive(Hash)]
+union Foo5 { _v: () }
+#[derive(Ord)]
+union Foo6 { _v: () }
+#[derive(PartialOrd)]
+union Foo7 { _v: () }
+#[derive(Eq)]
+union Foo8 { _v: () }
+#[derive(PartialEq)]
+union Foo9 { _v: () }
+    "#,
+        expect![[r#"
+            78..118: this trait cannot be derived for unions
+            119..157: this trait cannot be derived for unions
+            158..195: this trait cannot be derived for unions
+            196..232: this trait cannot be derived for unions
+            233..276: this trait cannot be derived for unions
+            313..355: this trait cannot be derived for unions"#]],
+    );
+}
+
+#[test]
+fn default_enum_without_default_attr() {
+    check_errors(
+        r#"
+//- minicore: default, derive
+
+#[derive(Default)]
+enum Foo {
+    Bar,
+}
+    "#,
+        expect!["1..41: `#[derive(Default)]` on enum with no `#[default]`"],
+    );
+}
+
+#[test]
+fn generic_enum_default() {
+    check(
+        r#"
+//- minicore: default, derive
+
+#[derive(Default)]
+enum Foo<T> {
+    Bar(T),
+    #[default]
+    Baz,
+}
+"#,
+        expect![[r#"
+
+#[derive(Default)]
+enum Foo<T> {
+    Bar(T),
+    #[default]
+    Baz,
+}
+
+impl <T, > $crate::default::Default for Foo<T, > where {
+    fn default() -> Self {
+        Foo::Baz
+    }
+}"#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs
index 7aaa918d1c9..07210df8873 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs
@@ -38,16 +38,18 @@ pub struct TraitItems {
     pub macro_calls: ThinVec<(AstId<ast::Item>, MacroCallId)>,
 }
 
+#[salsa::tracked]
 impl TraitItems {
     #[inline]
-    pub(crate) fn trait_items_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitItems> {
-        db.trait_items_with_diagnostics(tr).0
+    pub(crate) fn query(db: &dyn DefDatabase, tr: TraitId) -> &TraitItems {
+        &Self::query_with_diagnostics(db, tr).0
     }
 
-    pub(crate) fn trait_items_with_diagnostics_query(
+    #[salsa::tracked(returns(ref))]
+    pub fn query_with_diagnostics(
         db: &dyn DefDatabase,
         tr: TraitId,
-    ) -> (Arc<TraitItems>, DefDiagnostics) {
+    ) -> (TraitItems, DefDiagnostics) {
         let ItemLoc { container: module_id, id: ast_id } = tr.lookup(db);
 
         let collector =
@@ -55,7 +57,7 @@ impl TraitItems {
         let source = ast_id.with_value(collector.ast_id_map.get(ast_id.value)).to_node(db);
         let (items, macro_calls, diagnostics) = collector.collect(source.assoc_item_list());
 
-        (Arc::new(TraitItems { macro_calls, items }), DefDiagnostics::new(diagnostics))
+        (TraitItems { macro_calls, items }, DefDiagnostics::new(diagnostics))
     }
 
     pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
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 78fdc275606..0c3274d849a 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
@@ -41,6 +41,7 @@ use crate::{
     macro_call_as_call_id,
     nameres::{
         BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, ModuleData, ModuleOrigin, ResolveMode,
+        assoc::TraitItems,
         attr_resolution::{attr_macro_as_call_id, derive_macro_as_call_id},
         crate_def_map,
         diagnostics::DefDiagnostic,
@@ -1020,8 +1021,7 @@ impl<'db> DefCollector<'db> {
                         let resolutions = if true {
                             vec![]
                         } else {
-                            self.db
-                                .trait_items(it)
+                            TraitItems::query(self.db, it)
                                 .items
                                 .iter()
                                 .map(|&(ref name, variant)| {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
index e8235b1c96f..4641b220daa 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
@@ -24,8 +24,8 @@ use crate::{
     item_scope::{BUILTIN_SCOPE, ImportOrExternCrate},
     item_tree::FieldsShape,
     nameres::{
-        BlockInfo, BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, crate_def_map,
-        sub_namespace_match,
+        BlockInfo, BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, assoc::TraitItems,
+        crate_def_map, sub_namespace_match,
     },
     per_ns::PerNs,
     visibility::{RawVisibility, Visibility},
@@ -584,8 +584,11 @@ impl DefMap {
                     // now resulting in a cycle.
                     // To properly implement this, trait item collection needs to be done in def map
                     // collection...
-                    let item =
-                        if true { None } else { db.trait_items(t).assoc_item_by_name(segment) };
+                    let item = if true {
+                        None
+                    } else {
+                        TraitItems::query(db, t).assoc_item_by_name(segment)
+                    };
                     return match item {
                         Some(item) => ResolvePathResult::new(
                             match item {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
index ba75dca3d3d..338851b715b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
@@ -172,7 +172,7 @@ fn no() {}
                 "ast_id_map_shim",
                 "parse_shim",
                 "real_span_map_shim",
-                "of_",
+                "EnumVariants::of_",
             ]
         "#]],
         expect![[r#"
@@ -181,7 +181,7 @@ fn no() {}
                 "ast_id_map_shim",
                 "file_item_tree_query",
                 "real_span_map_shim",
-                "of_",
+                "EnumVariants::of_",
             ]
         "#]],
     );
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs
index 377a545ebf4..1958eb6c6a1 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs
@@ -1,6 +1,6 @@
 //! Item signature IR definitions
 
-use std::ops::Not as _;
+use std::{cell::LazyCell, ops::Not as _};
 
 use bitflags::bitflags;
 use cfg::{CfgExpr, CfgOptions};
@@ -731,29 +731,26 @@ pub struct VariantFields {
     pub store: Arc<ExpressionStore>,
     pub shape: FieldsShape,
 }
+
+#[salsa::tracked]
 impl VariantFields {
-    #[inline]
+    #[salsa::tracked(returns(clone))]
     pub(crate) fn query(
         db: &dyn DefDatabase,
         id: VariantId,
     ) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
-        let (shape, (fields, store, source_map)) = match id {
+        let (shape, result) = match id {
             VariantId::EnumVariantId(id) => {
                 let loc = id.lookup(db);
                 let parent = loc.parent.lookup(db);
                 let source = loc.source(db);
                 let shape = adt_shape(source.value.kind());
-                let span_map = db.span_map(source.file_id);
-                let override_visibility = visibility_from_ast(
-                    db,
-                    source.value.parent_enum().visibility(),
-                    &mut |range| span_map.span_for_range(range).ctx,
-                );
+                let enum_vis = Some(source.value.parent_enum().visibility());
                 let fields = lower_field_list(
                     db,
                     parent.container,
                     source.map(|src| src.field_list()),
-                    Some(override_visibility),
+                    enum_vis,
                 );
                 (shape, fields)
             }
@@ -777,10 +774,29 @@ impl VariantFields {
                 (FieldsShape::Record, fields)
             }
         };
+        match result {
+            Some((fields, store, source_map)) => (
+                Arc::new(VariantFields { fields, store: Arc::new(store), shape }),
+                Arc::new(source_map),
+            ),
+            None => (
+                Arc::new(VariantFields {
+                    fields: Arena::default(),
+                    store: ExpressionStore::empty_singleton(),
+                    shape,
+                }),
+                ExpressionStoreSourceMap::empty_singleton(),
+            ),
+        }
+    }
 
-        (Arc::new(VariantFields { fields, store: Arc::new(store), shape }), Arc::new(source_map))
+    #[salsa::tracked(returns(deref))]
+    pub(crate) fn firewall(db: &dyn DefDatabase, id: VariantId) -> Arc<Self> {
+        Self::query(db, id).0
     }
+}
 
+impl VariantFields {
     pub fn len(&self) -> usize {
         self.fields.len()
     }
@@ -798,31 +814,24 @@ fn lower_field_list(
     db: &dyn DefDatabase,
     module: ModuleId,
     fields: InFile<Option<ast::FieldList>>,
-    override_visibility: Option<RawVisibility>,
-) -> (Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap) {
+    override_visibility: Option<Option<ast::Visibility>>,
+) -> Option<(Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap)> {
     let file_id = fields.file_id;
-    match fields.value {
-        Some(ast::FieldList::RecordFieldList(fields)) => lower_fields(
+    match fields.value? {
+        ast::FieldList::RecordFieldList(fields) => lower_fields(
             db,
             module,
             InFile::new(file_id, fields.fields().map(|field| (field.ty(), field))),
             |_, field| as_name_opt(field.name()),
             override_visibility,
         ),
-        Some(ast::FieldList::TupleFieldList(fields)) => lower_fields(
+        ast::FieldList::TupleFieldList(fields) => lower_fields(
             db,
             module,
             InFile::new(file_id, fields.fields().map(|field| (field.ty(), field))),
             |idx, _| Name::new_tuple_field(idx),
             override_visibility,
         ),
-        None => lower_fields(
-            db,
-            module,
-            InFile::new(file_id, std::iter::empty::<(Option<ast::Type>, ast::RecordField)>()),
-            |_, _| Name::missing(),
-            None,
-        ),
     }
 }
 
@@ -831,22 +840,34 @@ fn lower_fields<Field: ast::HasAttrs + ast::HasVisibility>(
     module: ModuleId,
     fields: InFile<impl Iterator<Item = (Option<ast::Type>, Field)>>,
     mut field_name: impl FnMut(usize, &Field) -> Name,
-    override_visibility: Option<RawVisibility>,
-) -> (Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap) {
-    let mut arena = Arena::new();
+    override_visibility: Option<Option<ast::Visibility>>,
+) -> Option<(Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap)> {
     let cfg_options = module.krate.cfg_options(db);
     let mut col = ExprCollector::new(db, module, fields.file_id);
+    let override_visibility = override_visibility.map(|vis| {
+        LazyCell::new(|| {
+            let span_map = db.span_map(fields.file_id);
+            visibility_from_ast(db, vis, &mut |range| span_map.span_for_range(range).ctx)
+        })
+    });
+
+    let mut arena = Arena::new();
     let mut idx = 0;
+    let mut has_fields = false;
     for (ty, field) in fields.value {
+        has_fields = true;
         match Attrs::is_cfg_enabled_for(db, &field, col.span_map(), cfg_options) {
             Ok(()) => {
                 let type_ref =
                     col.lower_type_ref_opt(ty, &mut ExprCollector::impl_trait_error_allocator);
-                let visibility = override_visibility.clone().unwrap_or_else(|| {
-                    visibility_from_ast(db, field.visibility(), &mut |range| {
-                        col.span_map().span_for_range(range).ctx
-                    })
-                });
+                let visibility = override_visibility.as_ref().map_or_else(
+                    || {
+                        visibility_from_ast(db, field.visibility(), &mut |range| {
+                            col.span_map().span_for_range(range).ctx
+                        })
+                    },
+                    |it| RawVisibility::clone(it),
+                );
                 let is_unsafe = field
                     .syntax()
                     .children_with_tokens()
@@ -867,9 +888,12 @@ fn lower_fields<Field: ast::HasAttrs + ast::HasVisibility>(
             }
         }
     }
+    if !has_fields {
+        return None;
+    }
     let store = col.store.finish();
     arena.shrink_to_fit();
-    (arena, store, col.source_map)
+    Some((arena, store, col.source_map))
 }
 
 #[derive(Debug, PartialEq, Eq)]
@@ -948,7 +972,7 @@ impl EnumVariants {
         self.variants.iter().all(|&(v, _, _)| {
             // The condition check order is slightly modified from rustc
             // to improve performance by early returning with relatively fast checks
-            let variant = &db.variant_fields(v.into());
+            let variant = v.fields(db);
             if !variant.fields().is_empty() {
                 return false;
             }
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 2514e88864f..b5eb84c25f2 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
@@ -273,7 +273,7 @@ pub(crate) fn field_visibilities_query(
     db: &dyn DefDatabase,
     variant_id: VariantId,
 ) -> Arc<ArenaMap<LocalFieldId, Visibility>> {
-    let variant_fields = db.variant_fields(variant_id);
+    let variant_fields = variant_id.fields(db);
     let fields = variant_fields.fields();
     if fields.is_empty() {
         return Arc::default();
diff --git a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml
index ed818c5be3f..80a3c084865 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 cov-mark = "2.0.0"
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
index 94c97713f06..986f8764f5c 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
@@ -433,20 +433,19 @@ fn unescape(s: &str) -> Option<Cow<'_, str>> {
     let mut buf = String::new();
     let mut prev_end = 0;
     let mut has_error = false;
-    unescape::unescape_unicode(s, unescape::Mode::Str, &mut |char_range, unescaped_char| match (
-        unescaped_char,
-        buf.capacity() == 0,
-    ) {
-        (Ok(c), false) => buf.push(c),
-        (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => {
-            prev_end = char_range.end
-        }
-        (Ok(c), true) => {
-            buf.reserve_exact(s.len());
-            buf.push_str(&s[..prev_end]);
-            buf.push(c);
+    unescape::unescape_str(s, |char_range, unescaped_char| {
+        match (unescaped_char, buf.capacity() == 0) {
+            (Ok(c), false) => buf.push(c),
+            (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => {
+                prev_end = char_range.end
+            }
+            (Ok(c), true) => {
+                buf.reserve_exact(s.len());
+                buf.push_str(&s[..prev_end]);
+                buf.push(c);
+            }
+            (Err(_), _) => has_error = true,
         }
-        (Err(_), _) => has_error = true,
     });
 
     match (has_error, buf.capacity() == 0) {
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 d135584a080..15e68ff95cd 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
@@ -458,6 +458,7 @@ fn expand_simple_derive(
     invoc_span: Span,
     tt: &tt::TopSubtree,
     trait_path: tt::TopSubtree,
+    allow_unions: bool,
     make_trait_body: impl FnOnce(&BasicAdtInfo) -> tt::TopSubtree,
 ) -> ExpandResult<tt::TopSubtree> {
     let info = match parse_adt(db, tt, invoc_span) {
@@ -469,6 +470,12 @@ fn expand_simple_derive(
             );
         }
     };
+    if !allow_unions && matches!(info.shape, AdtShape::Union) {
+        return ExpandResult::new(
+            tt::TopSubtree::empty(tt::DelimSpan::from_single(invoc_span)),
+            ExpandError::other(invoc_span, "this trait cannot be derived for unions"),
+        );
+    }
     ExpandResult::ok(expand_simple_derive_with_parsed(
         invoc_span,
         info,
@@ -535,7 +542,14 @@ fn copy_expand(
     tt: &tt::TopSubtree,
 ) -> ExpandResult<tt::TopSubtree> {
     let krate = dollar_crate(span);
-    expand_simple_derive(db, span, tt, quote! {span => #krate::marker::Copy }, |_| quote! {span =>})
+    expand_simple_derive(
+        db,
+        span,
+        tt,
+        quote! {span => #krate::marker::Copy },
+        true,
+        |_| quote! {span =>},
+    )
 }
 
 fn clone_expand(
@@ -544,7 +558,7 @@ fn clone_expand(
     tt: &tt::TopSubtree,
 ) -> ExpandResult<tt::TopSubtree> {
     let krate = dollar_crate(span);
-    expand_simple_derive(db, span, tt, quote! {span => #krate::clone::Clone }, |adt| {
+    expand_simple_derive(db, span, tt, quote! {span => #krate::clone::Clone }, true, |adt| {
         if matches!(adt.shape, AdtShape::Union) {
             let star = tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span };
             return quote! {span =>
@@ -599,41 +613,63 @@ fn default_expand(
     tt: &tt::TopSubtree,
 ) -> ExpandResult<tt::TopSubtree> {
     let krate = &dollar_crate(span);
-    expand_simple_derive(db, span, tt, quote! {span => #krate::default::Default }, |adt| {
-        let body = match &adt.shape {
-            AdtShape::Struct(fields) => {
-                let name = &adt.name;
-                fields.as_pattern_map(
-                    quote!(span =>#name),
+    let adt = match parse_adt(db, tt, span) {
+        Ok(info) => info,
+        Err(e) => {
+            return ExpandResult::new(
+                tt::TopSubtree::empty(tt::DelimSpan { open: span, close: span }),
+                e,
+            );
+        }
+    };
+    let (body, constrain_to_trait) = match &adt.shape {
+        AdtShape::Struct(fields) => {
+            let name = &adt.name;
+            let body = fields.as_pattern_map(
+                quote!(span =>#name),
+                span,
+                |_| quote!(span =>#krate::default::Default::default()),
+            );
+            (body, true)
+        }
+        AdtShape::Enum { default_variant, variants } => {
+            if let Some(d) = default_variant {
+                let (name, fields) = &variants[*d];
+                let adt_name = &adt.name;
+                let body = fields.as_pattern_map(
+                    quote!(span =>#adt_name :: #name),
                     span,
                     |_| quote!(span =>#krate::default::Default::default()),
-                )
+                );
+                (body, false)
+            } else {
+                return ExpandResult::new(
+                    tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
+                    ExpandError::other(span, "`#[derive(Default)]` on enum with no `#[default]`"),
+                );
             }
-            AdtShape::Enum { default_variant, variants } => {
-                if let Some(d) = default_variant {
-                    let (name, fields) = &variants[*d];
-                    let adt_name = &adt.name;
-                    fields.as_pattern_map(
-                        quote!(span =>#adt_name :: #name),
-                        span,
-                        |_| quote!(span =>#krate::default::Default::default()),
-                    )
-                } else {
-                    // FIXME: Return expand error here
-                    quote!(span =>)
+        }
+        AdtShape::Union => {
+            return ExpandResult::new(
+                tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
+                ExpandError::other(span, "this trait cannot be derived for unions"),
+            );
+        }
+    };
+    ExpandResult::ok(expand_simple_derive_with_parsed(
+        span,
+        adt,
+        quote! {span => #krate::default::Default },
+        |_adt| {
+            quote! {span =>
+                fn default() -> Self {
+                    #body
                 }
             }
-            AdtShape::Union => {
-                // FIXME: Return expand error here
-                quote!(span =>)
-            }
-        };
-        quote! {span =>
-            fn default() -> Self {
-                #body
-            }
-        }
-    })
+        },
+        constrain_to_trait,
+        tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
+    ))
 }
 
 fn debug_expand(
@@ -642,7 +678,7 @@ fn debug_expand(
     tt: &tt::TopSubtree,
 ) -> ExpandResult<tt::TopSubtree> {
     let krate = &dollar_crate(span);
-    expand_simple_derive(db, span, tt, quote! {span => #krate::fmt::Debug }, |adt| {
+    expand_simple_derive(db, span, tt, quote! {span => #krate::fmt::Debug }, false, |adt| {
         let for_variant = |name: String, v: &VariantShape| match v {
             VariantShape::Struct(fields) => {
                 let for_fields = fields.iter().map(|it| {
@@ -697,10 +733,7 @@ fn debug_expand(
                     }
                 })
                 .collect(),
-            AdtShape::Union => {
-                // FIXME: Return expand error here
-                vec![]
-            }
+            AdtShape::Union => unreachable!(),
         };
         quote! {span =>
             fn fmt(&self, f: &mut #krate::fmt::Formatter) -> #krate::fmt::Result {
@@ -718,11 +751,7 @@ fn hash_expand(
     tt: &tt::TopSubtree,
 ) -> ExpandResult<tt::TopSubtree> {
     let krate = &dollar_crate(span);
-    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 =>};
-        }
+    expand_simple_derive(db, span, tt, quote! {span => #krate::hash::Hash }, false, |adt| {
         if matches!(&adt.shape, AdtShape::Enum { variants, .. } if variants.is_empty()) {
             let star = tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span };
             return quote! {span =>
@@ -769,7 +798,14 @@ fn eq_expand(
     tt: &tt::TopSubtree,
 ) -> ExpandResult<tt::TopSubtree> {
     let krate = dollar_crate(span);
-    expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::Eq }, |_| quote! {span =>})
+    expand_simple_derive(
+        db,
+        span,
+        tt,
+        quote! {span => #krate::cmp::Eq },
+        true,
+        |_| quote! {span =>},
+    )
 }
 
 fn partial_eq_expand(
@@ -778,11 +814,7 @@ fn partial_eq_expand(
     tt: &tt::TopSubtree,
 ) -> ExpandResult<tt::TopSubtree> {
     let krate = dollar_crate(span);
-    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 =>};
-        }
+    expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::PartialEq }, false, |adt| {
         let name = &adt.name;
 
         let (self_patterns, other_patterns) = self_and_other_patterns(adt, name, span);
@@ -854,7 +886,7 @@ fn ord_expand(
     tt: &tt::TopSubtree,
 ) -> ExpandResult<tt::TopSubtree> {
     let krate = &dollar_crate(span);
-    expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::Ord }, |adt| {
+    expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::Ord }, false, |adt| {
         fn compare(
             krate: &tt::Ident,
             left: tt::TopSubtree,
@@ -873,10 +905,6 @@ fn ord_expand(
                 }
             }
         }
-        if matches!(adt.shape, AdtShape::Union) {
-            // FIXME: Return expand error here
-            return quote!(span =>);
-        }
         let (self_patterns, other_patterns) = self_and_other_patterns(adt, &adt.name, span);
         let arms = izip!(self_patterns, other_patterns, adt.shape.field_names(span)).map(
             |(pat1, pat2, fields)| {
@@ -916,7 +944,7 @@ fn partial_ord_expand(
     tt: &tt::TopSubtree,
 ) -> ExpandResult<tt::TopSubtree> {
     let krate = &dollar_crate(span);
-    expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::PartialOrd }, |adt| {
+    expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::PartialOrd }, false, |adt| {
         fn compare(
             krate: &tt::Ident,
             left: tt::TopSubtree,
@@ -935,10 +963,6 @@ fn partial_ord_expand(
                 }
             }
         }
-        if matches!(adt.shape, AdtShape::Union) {
-            // FIXME: Return expand error here
-            return quote!(span =>);
-        }
         let left = quote!(span =>#krate::intrinsics::discriminant_value(self));
         let right = quote!(span =>#krate::intrinsics::discriminant_value(other));
 
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 3180b8dae10..800b40a9e7e 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
@@ -7,12 +7,13 @@ use intern::{
     Symbol,
     sym::{self},
 };
+use itertools::Itertools;
 use mbe::{DelimiterKind, expect_fragment};
 use span::{Edition, FileId, Span};
 use stdx::format_to;
 use syntax::{
     format_smolstr,
-    unescape::{Mode, unescape_byte, unescape_char, unescape_unicode},
+    unescape::{unescape_byte, unescape_char, unescape_str},
 };
 use syntax_bridge::syntax_node_to_token_tree;
 
@@ -430,7 +431,7 @@ fn compile_error_expand(
                 kind: tt::LitKind::Str | tt::LitKind::StrRaw(_),
                 suffix: _,
             })),
-        ] => ExpandError::other(span, Box::from(unescape_str(text).as_str())),
+        ] => ExpandError::other(span, Box::from(unescape_symbol(text).as_str())),
         _ => ExpandError::other(span, "`compile_error!` argument must be a string"),
     };
 
@@ -481,7 +482,7 @@ fn concat_expand(
                         format_to!(text, "{}", it.symbol.as_str())
                     }
                     tt::LitKind::Str => {
-                        text.push_str(unescape_str(&it.symbol).as_str());
+                        text.push_str(unescape_symbol(&it.symbol).as_str());
                         record_span(it.span);
                     }
                     tt::LitKind::StrRaw(_) => {
@@ -681,52 +682,36 @@ fn relative_file(
 }
 
 fn parse_string(tt: &tt::TopSubtree) -> Result<(Symbol, Span), ExpandError> {
-    let delimiter = tt.top_subtree().delimiter;
-    tt.iter()
-        .next()
-        .ok_or(delimiter.open.cover(delimiter.close))
-        .and_then(|tt| match tt {
+    let mut tt = TtElement::Subtree(tt.top_subtree(), tt.iter());
+    (|| {
+        // FIXME: We wrap expression fragments in parentheses which can break this expectation
+        // here
+        // Remove this once we handle none delims correctly
+        while let TtElement::Subtree(sub, tt_iter) = &mut tt
+            && let DelimiterKind::Parenthesis | DelimiterKind::Invisible = sub.delimiter.kind
+        {
+            tt =
+                tt_iter.exactly_one().map_err(|_| sub.delimiter.open.cover(sub.delimiter.close))?;
+        }
+
+        match tt {
             TtElement::Leaf(tt::Leaf::Literal(tt::Literal {
                 symbol: text,
                 span,
                 kind: tt::LitKind::Str,
                 suffix: _,
-            })) => Ok((unescape_str(text), *span)),
+            })) => Ok((unescape_symbol(text), *span)),
             TtElement::Leaf(tt::Leaf::Literal(tt::Literal {
                 symbol: text,
                 span,
                 kind: tt::LitKind::StrRaw(_),
                 suffix: _,
             })) => Ok((text.clone(), *span)),
-            // FIXME: We wrap expression fragments in parentheses which can break this expectation
-            // here
-            // Remove this once we handle none delims correctly
-            TtElement::Subtree(tt, mut tt_iter)
-                if tt.delimiter.kind == DelimiterKind::Parenthesis =>
-            {
-                tt_iter
-                    .next()
-                    .and_then(|tt| match tt {
-                        TtElement::Leaf(tt::Leaf::Literal(tt::Literal {
-                            symbol: text,
-                            span,
-                            kind: tt::LitKind::Str,
-                            suffix: _,
-                        })) => Some((unescape_str(text), *span)),
-                        TtElement::Leaf(tt::Leaf::Literal(tt::Literal {
-                            symbol: text,
-                            span,
-                            kind: tt::LitKind::StrRaw(_),
-                            suffix: _,
-                        })) => Some((text.clone(), *span)),
-                        _ => None,
-                    })
-                    .ok_or(delimiter.open.cover(delimiter.close))
-            }
             TtElement::Leaf(l) => Err(*l.span()),
             TtElement::Subtree(tt, _) => Err(tt.delimiter.open.cover(tt.delimiter.close)),
-        })
-        .map_err(|span| ExpandError::other(span, "expected string literal"))
+        }
+    })()
+    .map_err(|span| ExpandError::other(span, "expected string literal"))
 }
 
 fn include_expand(
@@ -897,11 +882,11 @@ fn quote_expand(
     )
 }
 
-fn unescape_str(s: &Symbol) -> Symbol {
+fn unescape_symbol(s: &Symbol) -> Symbol {
     if s.as_str().contains('\\') {
         let s = s.as_str();
         let mut buf = String::with_capacity(s.len());
-        unescape_unicode(s, Mode::Str, &mut |_, c| {
+        unescape_str(s, |_, c| {
             if let Ok(c) = c {
                 buf.push(c)
             }
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 7e9928c41ff..888c1405a6b 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
@@ -145,7 +145,7 @@ pub trait ExpandDatabase: RootQueryDb {
     fn syntax_context(&self, file: HirFileId, edition: Edition) -> SyntaxContext;
 }
 
-#[salsa_macros::interned(no_lifetime, id = span::SyntaxContext)]
+#[salsa_macros::interned(no_lifetime, id = span::SyntaxContext, revisions = usize::MAX)]
 pub struct SyntaxContextWrapper {
     pub data: SyntaxContext,
 }
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 a73a22370d2..6730b337d35 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs
@@ -315,11 +315,11 @@ impl<SN: Borrow<SyntaxNode>> InFile<SN> {
     }
 
     /// Falls back to the macro call range if the node cannot be mapped up fully.
-    pub fn original_file_range_with_macro_call_body(
+    pub fn original_file_range_with_macro_call_input(
         self,
         db: &dyn db::ExpandDatabase,
     ) -> FileRange {
-        self.borrow().map(SyntaxNode::text_range).original_node_file_range_with_macro_call_body(db)
+        self.borrow().map(SyntaxNode::text_range).original_node_file_range_with_macro_call_input(db)
     }
 
     pub fn original_syntax_node_rooted(
@@ -465,7 +465,7 @@ impl InFile<TextRange> {
         }
     }
 
-    pub fn original_node_file_range_with_macro_call_body(
+    pub fn original_node_file_range_with_macro_call_input(
         self,
         db: &dyn db::ExpandDatabase,
     ) -> FileRange {
@@ -476,7 +476,7 @@ impl InFile<TextRange> {
                     Some(it) => it,
                     _ => {
                         let loc = db.lookup_intern_macro_call(mac_file);
-                        loc.kind.original_call_range_with_body(db)
+                        loc.kind.original_call_range_with_input(db)
                     }
                 }
             }
@@ -497,6 +497,18 @@ impl InFile<TextRange> {
             }
         }
     }
+
+    pub fn original_node_file_range_rooted_opt(
+        self,
+        db: &dyn db::ExpandDatabase,
+    ) -> Option<FileRange> {
+        match self.file_id {
+            HirFileId::FileId(file_id) => Some(FileRange { file_id, range: self.value }),
+            HirFileId::MacroFile(mac_file) => {
+                map_node_range_up_rooted(db, &db.expansion_span_map(mac_file), self.value)
+            }
+        }
+    }
 }
 
 impl<N: AstNode> InFile<N> {
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 6ecac1463f5..ac61b220097 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
@@ -199,9 +199,9 @@ impl ExpandErrorKind {
             },
             &ExpandErrorKind::MissingProcMacroExpander(def_crate) => {
                 match db.proc_macros_for_crate(def_crate).as_ref().and_then(|it| it.get_error()) {
-                    Some((e, hard_err)) => RenderedExpandError {
-                        message: e.to_owned(),
-                        error: hard_err,
+                    Some(e) => RenderedExpandError {
+                        message: e.to_string(),
+                        error: e.is_hard_error(),
                         kind: RenderedExpandError::GENERAL_KIND,
                     },
                     None => RenderedExpandError {
@@ -688,8 +688,11 @@ impl MacroCallKind {
 
     /// Returns the original file range that best describes the location of this macro call.
     ///
-    /// Unlike `MacroCallKind::original_call_range`, this also spans the item of attributes and derives.
-    pub fn original_call_range_with_body(self, db: &dyn ExpandDatabase) -> FileRange {
+    /// This spans the entire macro call, including its input. That is for
+    /// - fn_like! {}, it spans the path and token tree
+    /// - #\[derive], it spans the `#[derive(...)]` attribute and the annotated item
+    /// - #\[attr], it spans the `#[attr(...)]` attribute and the annotated item
+    pub fn original_call_range_with_input(self, db: &dyn ExpandDatabase) -> FileRange {
         let mut kind = self;
         let file_id = loop {
             match kind.file_id() {
@@ -712,8 +715,8 @@ impl MacroCallKind {
     /// Returns the original file range that best describes the location of this macro call.
     ///
     /// Here we try to roughly match what rustc does to improve diagnostics: fn-like macros
-    /// get the whole `ast::MacroCall`, attribute macros get the attribute's range, and derives
-    /// get only the specific derive that is being referred to.
+    /// get the macro path (rustc shows the whole `ast::MacroCall`), attribute macros get the
+    /// attribute's range, and derives get only the specific derive that is being referred to.
     pub fn original_call_range(self, db: &dyn ExpandDatabase) -> FileRange {
         let mut kind = self;
         let file_id = loop {
@@ -726,7 +729,14 @@ impl MacroCallKind {
         };
 
         let range = match kind {
-            MacroCallKind::FnLike { ast_id, .. } => ast_id.to_ptr(db).text_range(),
+            MacroCallKind::FnLike { ast_id, .. } => {
+                let node = ast_id.to_node(db);
+                node.path()
+                    .unwrap()
+                    .syntax()
+                    .text_range()
+                    .cover(node.excl_token().unwrap().text_range())
+            }
             MacroCallKind::Derive { ast_id, derive_attr_index, .. } => {
                 // FIXME: should be the range of the macro name, not the whole derive
                 // FIXME: handle `cfg_attr`
@@ -1056,7 +1066,7 @@ impl ExpandTo {
 
 intern::impl_internable!(ModPath, attrs::AttrInput);
 
-#[salsa_macros::interned(no_lifetime, debug)]
+#[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)]
 #[doc(alias = "MacroFileId")]
 pub struct MacroCallId {
     pub loc: MacroCallLoc,
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 217d991d110..679f61112ad 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
@@ -179,9 +179,10 @@ impl Name {
         self.symbol.as_str()
     }
 
+    #[inline]
     pub fn display<'a>(
         &'a self,
-        db: &dyn crate::db::ExpandDatabase,
+        db: &dyn salsa::Database,
         edition: Edition,
     ) -> impl fmt::Display + 'a {
         _ = db;
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/prettify_macro_expansion_.rs b/src/tools/rust-analyzer/crates/hir-expand/src/prettify_macro_expansion_.rs
index 6134c3a36b9..6431d46d39e 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/prettify_macro_expansion_.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/prettify_macro_expansion_.rs
@@ -46,7 +46,7 @@ pub fn prettify_macro_expansion(
                     } else if let Some(crate_name) = &macro_def_crate.extra_data(db).display_name {
                         make::tokens::ident(crate_name.crate_name().as_str())
                     } else {
-                        return dollar_crate.clone();
+                        dollar_crate.clone()
                     }
                 });
             if replacement.text() == "$crate" {
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
index 1c8ebb6f535..f97d721dfa8 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
@@ -4,7 +4,7 @@ use core::fmt;
 use std::any::Any;
 use std::{panic::RefUnwindSafe, sync};
 
-use base_db::{Crate, CrateBuilderId, CratesIdMap, Env};
+use base_db::{Crate, CrateBuilderId, CratesIdMap, Env, ProcMacroLoadingError};
 use intern::Symbol;
 use rustc_hash::FxHashMap;
 use span::Span;
@@ -53,8 +53,8 @@ pub enum ProcMacroExpansionError {
     System(String),
 }
 
-pub type ProcMacroLoadResult = Result<Vec<ProcMacro>, (String, bool)>;
-type StoredProcMacroLoadResult = Result<Box<[ProcMacro]>, (Box<str>, bool)>;
+pub type ProcMacroLoadResult = Result<Vec<ProcMacro>, ProcMacroLoadingError>;
+type StoredProcMacroLoadResult = Result<Box<[ProcMacro]>, ProcMacroLoadingError>;
 
 #[derive(Default, Debug)]
 pub struct ProcMacrosBuilder(FxHashMap<CrateBuilderId, Arc<CrateProcMacros>>);
@@ -77,9 +77,7 @@ impl ProcMacrosBuilder {
             proc_macros_crate,
             match proc_macro {
                 Ok(it) => Arc::new(CrateProcMacros(Ok(it.into_boxed_slice()))),
-                Err((e, hard_err)) => {
-                    Arc::new(CrateProcMacros(Err((e.into_boxed_str(), hard_err))))
-                }
+                Err(e) => Arc::new(CrateProcMacros(Err(e))),
             },
         );
     }
@@ -139,8 +137,8 @@ impl CrateProcMacros {
         )
     }
 
-    pub fn get_error(&self) -> Option<(&str, bool)> {
-        self.0.as_ref().err().map(|(e, hard_err)| (&**e, *hard_err))
+    pub fn get_error(&self) -> Option<&ProcMacroLoadingError> {
+        self.0.as_ref().err()
     }
 
     /// Fetch the [`CustomProcMacroExpander`]s and their corresponding names for the given crate.
diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
index 8b65126e7b7..7cc0a26d37c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 cov-mark = "2.0.0"
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
index 7acc9456ec9..cc8f7bf04a5 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
@@ -208,7 +208,7 @@ pub(crate) fn deref_by_trait(
     };
     let trait_id = trait_id()?;
     let target =
-        db.trait_items(trait_id).associated_type_by_name(&Name::new_symbol_root(sym::Target))?;
+        trait_id.trait_items(db).associated_type_by_name(&Name::new_symbol_root(sym::Target))?;
 
     let projection = {
         let b = TyBuilder::subst_for_def(db, trait_id, None);
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 79454428112..26b635298a6 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
@@ -315,9 +315,8 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
             crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => {
                 if let Some((future_trait, future_output)) =
                     LangItem::Future.resolve_trait(self.db, self.krate).and_then(|trait_| {
-                        let alias = self
-                            .db
-                            .trait_items(trait_)
+                        let alias = trait_
+                            .trait_items(self.db)
                             .associated_type_by_name(&Name::new_symbol_root(sym::Output))?;
                         Some((trait_, alias))
                     })
@@ -711,7 +710,7 @@ pub(crate) fn trait_datum_query(
     };
     let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars);
     let associated_ty_ids =
-        db.trait_items(trait_).associated_types().map(to_assoc_type_id).collect();
+        trait_.trait_items(db).associated_types().map(to_assoc_type_id).collect();
     let trait_datum_bound = rust_ir::TraitDatumBound { where_clauses };
     let well_known = db.lang_attr(trait_.into()).and_then(well_known_trait_from_lang_item);
     let trait_datum = TraitDatum {
@@ -802,7 +801,7 @@ pub(crate) fn adt_datum_query(
 
     // this slows down rust-analyzer by quite a bit unfortunately, so enabling this is currently not worth it
     let _variant_id_to_fields = |id: VariantId| {
-        let variant_data = &id.variant_data(db);
+        let variant_data = &id.fields(db);
         let fields = if variant_data.fields().is_empty() {
             vec![]
         } else {
@@ -879,7 +878,7 @@ fn impl_def_datum(db: &dyn HirDatabase, krate: Crate, impl_id: hir_def::ImplId)
     let polarity = if negative { rust_ir::Polarity::Negative } else { rust_ir::Polarity::Positive };
 
     let impl_datum_bound = rust_ir::ImplDatumBound { trait_ref, where_clauses };
-    let trait_data = db.trait_items(trait_);
+    let trait_data = trait_.trait_items(db);
     let associated_ty_value_ids = impl_id
         .impl_items(db)
         .items
@@ -931,8 +930,9 @@ fn type_alias_associated_ty_value(
         .into_value_and_skipped_binders()
         .0; // we don't return any assoc ty values if the impl'd trait can't be resolved
 
-    let assoc_ty = db
-        .trait_items(trait_ref.hir_trait_id())
+    let assoc_ty = trait_ref
+        .hir_trait_id()
+        .trait_items(db)
         .associated_type_by_name(&type_alias_data.name)
         .expect("assoc ty value should not exist"); // validated when building the impl data as well
     let (ty, binders) = db.ty(type_alias.into()).into_value_and_skipped_binders();
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
index 1029969992c..5d3be07f3db 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
@@ -237,15 +237,6 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
 
     // Interned IDs for Chalk integration
     #[salsa::interned]
-    fn intern_type_or_const_param_id(
-        &self,
-        param_id: TypeOrConstParamId,
-    ) -> InternedTypeOrConstParamId;
-
-    #[salsa::interned]
-    fn intern_lifetime_param_id(&self, param_id: LifetimeParamId) -> InternedLifetimeParamId;
-
-    #[salsa::interned]
     fn intern_impl_trait_id(&self, id: ImplTraitId) -> InternedOpaqueTyId;
 
     #[salsa::interned]
@@ -282,9 +273,8 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
 
     #[salsa::invoke(crate::variance::variances_of)]
     #[salsa::cycle(
-        // cycle_fn = crate::variance::variances_of_cycle_fn,
-        // cycle_initial = crate::variance::variances_of_cycle_initial,
-        cycle_result = crate::variance::variances_of_cycle_initial,
+        cycle_fn = crate::variance::variances_of_cycle_fn,
+        cycle_initial = crate::variance::variances_of_cycle_initial,
     )]
     fn variances_of(&self, def: GenericDefId) -> Option<Arc<[crate::variance::Variance]>>;
 
@@ -329,9 +319,31 @@ fn hir_database_is_dyn_compatible() {
     fn _assert_dyn_compatible(_: &dyn HirDatabase) {}
 }
 
-impl_intern_key!(InternedTypeOrConstParamId, TypeOrConstParamId);
+#[salsa_macros::interned(no_lifetime, revisions = usize::MAX)]
+#[derive(PartialOrd, Ord)]
+pub struct InternedTypeOrConstParamId {
+    pub loc: TypeOrConstParamId,
+}
+impl ::std::fmt::Debug for InternedTypeOrConstParamId {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+        f.debug_tuple(stringify!(InternedTypeOrConstParamId))
+            .field(&format_args!("{:04x}", self.0.index()))
+            .finish()
+    }
+}
 
-impl_intern_key!(InternedLifetimeParamId, LifetimeParamId);
+#[salsa_macros::interned(no_lifetime, revisions = usize::MAX)]
+#[derive(PartialOrd, Ord)]
+pub struct InternedLifetimeParamId {
+    pub loc: LifetimeParamId,
+}
+impl ::std::fmt::Debug for InternedLifetimeParamId {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+        f.debug_tuple(stringify!(InternedLifetimeParamId))
+            .field(&format_args!("{:04x}", self.0.index()))
+            .finish()
+    }
+}
 
 impl_intern_key!(InternedConstParamId, ConstParamId);
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
index 1873f12fb7c..9c0f8f40080 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
@@ -307,7 +307,7 @@ impl<'a> DeclValidator<'a> {
 
     /// Check incorrect names for struct fields.
     fn validate_struct_fields(&mut self, struct_id: StructId) {
-        let data = self.db.variant_fields(struct_id.into());
+        let data = struct_id.fields(self.db);
         if data.shape != FieldsShape::Record {
             return;
         };
@@ -468,7 +468,7 @@ impl<'a> DeclValidator<'a> {
 
     /// Check incorrect names for fields of enum variant.
     fn validate_enum_variant_fields(&mut self, variant_id: EnumVariantId) {
-        let variant_data = self.db.variant_fields(variant_id.into());
+        let variant_data = variant_id.fields(self.db);
         if variant_data.shape != FieldsShape::Record {
             return;
         };
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
index df2eb410b99..5d56957be6d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
@@ -494,7 +494,7 @@ impl FilterMapNextChecker {
                 Some(next_function_id),
                 match next_function_id.lookup(db).container {
                     ItemContainerId::TraitId(iterator_trait_id) => {
-                        let iterator_trait_items = &db.trait_items(iterator_trait_id).items;
+                        let iterator_trait_items = &iterator_trait_id.trait_items(db).items;
                         iterator_trait_items.iter().find_map(|(name, it)| match it {
                             &AssocItemId::FunctionId(id) if *name == sym::filter_map => Some(id),
                             _ => None,
@@ -558,7 +558,7 @@ pub fn record_literal_missing_fields(
         return None;
     }
 
-    let variant_data = variant_def.variant_data(db);
+    let variant_data = variant_def.fields(db);
 
     let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
     let missed_fields: Vec<LocalFieldId> = variant_data
@@ -588,7 +588,7 @@ pub fn record_pattern_missing_fields(
         return None;
     }
 
-    let variant_data = variant_def.variant_data(db);
+    let variant_data = variant_def.fields(db);
 
     let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
     let missed_fields: Vec<LocalFieldId> = variant_data
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
index 916876d4ac9..c3ab5aff3db 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
@@ -25,7 +25,6 @@ use crate::{
     db::HirDatabase,
     display::{HirDisplay, HirDisplayError, HirFormatter},
     infer::BindingMode,
-    lang_items::is_box,
 };
 
 use self::pat_util::EnumerateAndAdjustIterator;
@@ -77,7 +76,7 @@ pub(crate) enum PatKind {
         subpatterns: Vec<FieldPat>,
     },
 
-    /// `box P`, `&P`, `&mut P`, etc.
+    /// `&P`, `&mut P`, etc.
     Deref {
         subpattern: Pat,
     },
@@ -169,13 +168,13 @@ impl<'a> PatCtxt<'a> {
             }
 
             hir_def::hir::Pat::TupleStruct { ref args, ellipsis, .. } if variant.is_some() => {
-                let expected_len = variant.unwrap().variant_data(self.db).fields().len();
+                let expected_len = variant.unwrap().fields(self.db).fields().len();
                 let subpatterns = self.lower_tuple_subpats(args, expected_len, ellipsis);
                 self.lower_variant_or_leaf(pat, ty, subpatterns)
             }
 
             hir_def::hir::Pat::Record { ref args, .. } if variant.is_some() => {
-                let variant_data = variant.unwrap().variant_data(self.db);
+                let variant_data = variant.unwrap().fields(self.db);
                 let subpatterns = args
                     .iter()
                     .map(|field| {
@@ -345,7 +344,7 @@ impl HirDisplay for Pat {
                         )?,
                     };
 
-                    let variant_data = variant.variant_data(f.db);
+                    let variant_data = variant.fields(f.db);
                     if variant_data.shape == FieldsShape::Record {
                         write!(f, " {{ ")?;
 
@@ -377,7 +376,7 @@ impl HirDisplay for Pat {
                 }
 
                 let num_fields =
-                    variant.map_or(subpatterns.len(), |v| v.variant_data(f.db).fields().len());
+                    variant.map_or(subpatterns.len(), |v| v.fields(f.db).fields().len());
                 if num_fields != 0 || variant.is_none() {
                     write!(f, "(")?;
                     let subpats = (0..num_fields).map(|i| {
@@ -406,7 +405,6 @@ impl HirDisplay for Pat {
             }
             PatKind::Deref { subpattern } => {
                 match self.ty.kind(Interner) {
-                    TyKind::Adt(adt, _) if is_box(f.db, adt.0) => write!(f, "box ")?,
                     &TyKind::Ref(mutbl, ..) => {
                         write!(f, "&{}", if mutbl == Mutability::Mut { "mut " } else { "" })?
                     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
index 2873a3e09e7..22b7f5ac9fd 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
@@ -6,7 +6,7 @@ use std::fmt;
 use hir_def::{DefWithBodyId, EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId};
 use intern::sym;
 use rustc_pattern_analysis::{
-    Captures, IndexVec, PatCx, PrivateUninhabitedField,
+    IndexVec, PatCx, PrivateUninhabitedField,
     constructor::{Constructor, ConstructorSet, VariantVisibility},
     usefulness::{PlaceValidity, UsefulnessReport, compute_match_usefulness},
 };
@@ -21,7 +21,7 @@ use crate::{
     inhabitedness::{is_enum_variant_uninhabited_from, is_ty_uninhabited_from},
 };
 
-use super::{FieldPat, Pat, PatKind, is_box};
+use super::{FieldPat, Pat, PatKind};
 
 use Constructor::*;
 
@@ -138,15 +138,15 @@ impl<'db> MatchCheckCtx<'db> {
     }
 
     // This lists the fields of a variant along with their types.
-    fn list_variant_fields<'a>(
-        &'a self,
-        ty: &'a Ty,
+    fn list_variant_fields(
+        &self,
+        ty: &Ty,
         variant: VariantId,
-    ) -> impl Iterator<Item = (LocalFieldId, Ty)> + Captures<'a> + Captures<'db> {
+    ) -> impl Iterator<Item = (LocalFieldId, Ty)> {
         let (_, substs) = ty.as_adt().unwrap();
 
         let field_tys = self.db.field_types(variant);
-        let fields_len = variant.variant_data(self.db).fields().len() as u32;
+        let fields_len = variant.fields(self.db).fields().len() as u32;
 
         (0..fields_len).map(|idx| LocalFieldId::from_raw(idx.into())).map(move |fid| {
             let ty = field_tys[fid].clone().substitute(Interner, substs);
@@ -170,8 +170,6 @@ impl<'db> MatchCheckCtx<'db> {
             }
             PatKind::Deref { subpattern } => {
                 ctor = match pat.ty.kind(Interner) {
-                    // This is a box pattern.
-                    TyKind::Adt(adt, _) if is_box(self.db, adt.0) => Struct,
                     TyKind::Ref(..) => Ref,
                     _ => {
                         never!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, &pat.ty);
@@ -194,23 +192,6 @@ impl<'db> MatchCheckCtx<'db> {
                         ctor = Struct;
                         arity = substs.len(Interner);
                     }
-                    TyKind::Adt(adt, _) if is_box(self.db, adt.0) => {
-                        // The only legal patterns of type `Box` (outside `std`) are `_` and box
-                        // patterns. If we're here we can assume this is a box pattern.
-                        // FIXME(Nadrieril): A `Box` can in theory be matched either with `Box(_,
-                        // _)` or a box pattern. As a hack to avoid an ICE with the former, we
-                        // ignore other fields than the first one. This will trigger an error later
-                        // anyway.
-                        // See https://github.com/rust-lang/rust/issues/82772 ,
-                        // explanation: https://github.com/rust-lang/rust/pull/82789#issuecomment-796921977
-                        // The problem is that we can't know from the type whether we'll match
-                        // normally or through box-patterns. We'll have to figure out a proper
-                        // solution when we introduce generalized deref patterns. Also need to
-                        // prevent mixing of those two options.
-                        fields.retain(|ipat| ipat.idx == 0);
-                        ctor = Struct;
-                        arity = 1;
-                    }
                     &TyKind::Adt(AdtId(adt), _) => {
                         ctor = match pat.kind.as_ref() {
                             PatKind::Leaf { .. } if matches!(adt, hir_def::AdtId::UnionId(_)) => {
@@ -229,7 +210,7 @@ impl<'db> MatchCheckCtx<'db> {
                             }
                         };
                         let variant = Self::variant_id_for_adt(self.db, &ctor, adt).unwrap();
-                        arity = variant.variant_data(self.db).fields().len();
+                        arity = variant.fields(self.db).fields().len();
                     }
                     _ => {
                         never!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, &pat.ty);
@@ -277,12 +258,6 @@ impl<'db> MatchCheckCtx<'db> {
                         })
                         .collect(),
                 },
-                TyKind::Adt(adt, _) if is_box(self.db, adt.0) => {
-                    // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside
-                    // of `std`). So this branch is only reachable when the feature is enabled and
-                    // the pattern is a box pattern.
-                    PatKind::Deref { subpattern: subpatterns.next().unwrap() }
-                }
                 TyKind::Adt(adt, substs) => {
                     let variant = Self::variant_id_for_adt(self.db, pat.ctor(), adt.0).unwrap();
                     let subpatterns = self
@@ -343,14 +318,8 @@ impl PatCx for MatchCheckCtx<'_> {
             Struct | Variant(_) | UnionField => match *ty.kind(Interner) {
                 TyKind::Tuple(arity, ..) => arity,
                 TyKind::Adt(AdtId(adt), ..) => {
-                    if is_box(self.db, adt) {
-                        // The only legal patterns of type `Box` (outside `std`) are `_` and box
-                        // patterns. If we're here we can assume this is a box pattern.
-                        1
-                    } else {
-                        let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap();
-                        variant.variant_data(self.db).fields().len()
-                    }
+                    let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap();
+                    variant.fields(self.db).fields().len()
                 }
                 _ => {
                     never!("Unexpected type for `Single` constructor: {:?}", ty);
@@ -383,29 +352,22 @@ impl PatCx for MatchCheckCtx<'_> {
                     tys.cloned().map(|ty| (ty, PrivateUninhabitedField(false))).collect()
                 }
                 TyKind::Ref(.., rty) => single(rty.clone()),
-                &TyKind::Adt(AdtId(adt), ref substs) => {
-                    if is_box(self.db, adt) {
-                        // The only legal patterns of type `Box` (outside `std`) are `_` and box
-                        // patterns. If we're here we can assume this is a box pattern.
-                        let subst_ty = substs.at(Interner, 0).assert_ty_ref(Interner).clone();
-                        single(subst_ty)
-                    } else {
-                        let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap();
-
-                        let visibilities = LazyCell::new(|| self.db.field_visibilities(variant));
-
-                        self.list_variant_fields(ty, variant)
-                            .map(move |(fid, ty)| {
-                                let is_visible = || {
-                                    matches!(adt, hir_def::AdtId::EnumId(..))
-                                        || visibilities[fid].is_visible_from(self.db, self.module)
-                                };
-                                let is_uninhabited = self.is_uninhabited(&ty);
-                                let private_uninhabited = is_uninhabited && !is_visible();
-                                (ty, PrivateUninhabitedField(private_uninhabited))
-                            })
-                            .collect()
-                    }
+                &TyKind::Adt(AdtId(adt), ..) => {
+                    let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap();
+
+                    let visibilities = LazyCell::new(|| self.db.field_visibilities(variant));
+
+                    self.list_variant_fields(ty, variant)
+                        .map(move |(fid, ty)| {
+                            let is_visible = || {
+                                matches!(adt, hir_def::AdtId::EnumId(..))
+                                    || visibilities[fid].is_visible_from(self.db, self.module)
+                            };
+                            let is_uninhabited = self.is_uninhabited(&ty);
+                            let private_uninhabited = is_uninhabited && !is_visible();
+                            (ty, PrivateUninhabitedField(private_uninhabited))
+                        })
+                        .collect()
                 }
                 ty_kind => {
                     never!("Unexpected type for `{:?}` constructor: {:?}", ctor, ty_kind);
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 1aa7e0fcf88..810fe76f231 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -888,7 +888,7 @@ fn render_const_scalar(
                     write!(f, "{}", data.name.display(f.db, f.edition()))?;
                     let field_types = f.db.field_types(s.into());
                     render_variant_after_name(
-                        &f.db.variant_fields(s.into()),
+                        s.fields(f.db),
                         f,
                         &field_types,
                         f.db.trait_environment(adt.0.into()),
@@ -920,7 +920,7 @@ fn render_const_scalar(
                     )?;
                     let field_types = f.db.field_types(var_id.into());
                     render_variant_after_name(
-                        &f.db.variant_fields(var_id.into()),
+                        var_id.fields(f.db),
                         f,
                         &field_types,
                         f.db.trait_environment(adt.0.into()),
@@ -1394,7 +1394,7 @@ impl HirDisplay for Ty {
                         let future_trait =
                             LangItem::Future.resolve_trait(db, body.module(db).krate());
                         let output = future_trait.and_then(|t| {
-                            db.trait_items(t)
+                            t.trait_items(db)
                                 .associated_type_by_name(&Name::new_symbol_root(sym::Output))
                         });
                         write!(f, "impl ")?;
@@ -1432,10 +1432,10 @@ impl HirDisplay for Ty {
                 match f.closure_style {
                     ClosureStyle::Hide => return write!(f, "{TYPE_HINT_TRUNCATION}"),
                     ClosureStyle::ClosureWithId => {
-                        return write!(f, "{{closure#{:?}}}", id.0.as_u32());
+                        return write!(f, "{{closure#{:?}}}", id.0.index());
                     }
                     ClosureStyle::ClosureWithSubst => {
-                        write!(f, "{{closure#{:?}}}", id.0.as_u32())?;
+                        write!(f, "{{closure#{:?}}}", id.0.index())?;
                         return hir_fmt_generics(f, substs.as_slice(Interner), None, None);
                     }
                     _ => (),
@@ -2178,6 +2178,7 @@ impl HirDisplayWithExpressionStore for TypeRefId {
                         f.write_joined(
                             generic_params
                                 .where_predicates()
+                                .iter()
                                 .filter_map(|it| match it {
                                     WherePredicate::TypeBound { target, bound }
                                     | WherePredicate::ForLifetime { lifetimes: _, target, bound }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
index 48094945c11..30949c83bfa 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
@@ -101,7 +101,7 @@ where
 
     // rustc checks for non-lifetime binders here, but we don't support HRTB yet
 
-    let trait_data = db.trait_items(trait_);
+    let trait_data = trait_.trait_items(db);
     for (_, assoc_item) in &trait_data.items {
         dyn_compatibility_violation_for_assoc_item(db, trait_, *assoc_item, cb)?;
     }
@@ -164,7 +164,7 @@ fn predicates_reference_self(db: &dyn HirDatabase, trait_: TraitId) -> bool {
 
 // Same as the above, `predicates_reference_self`
 fn bounds_reference_self(db: &dyn HirDatabase, trait_: TraitId) -> bool {
-    let trait_data = db.trait_items(trait_);
+    let trait_data = trait_.trait_items(db);
     trait_data
         .items
         .iter()
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
index a3ed39934cd..f14872e68c3 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
@@ -60,7 +60,16 @@ impl Generics {
     }
 
     pub(crate) fn where_predicates(&self) -> impl Iterator<Item = &WherePredicate> {
-        self.params.where_predicates()
+        self.params.where_predicates().iter()
+    }
+
+    pub(crate) fn has_no_predicates(&self) -> bool {
+        self.params.has_no_predicates()
+            && self.parent_generics.as_ref().is_none_or(|g| g.params.has_no_predicates())
+    }
+
+    pub(crate) fn is_empty(&self) -> bool {
+        self.params.is_empty() && self.parent_generics.as_ref().is_none_or(|g| g.params.is_empty())
     }
 
     pub(crate) fn iter_id(&self) -> impl Iterator<Item = GenericParamId> + '_ {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index 80478f19371..e880438e3a7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -460,19 +460,17 @@ pub struct InferenceResult {
     /// Whenever a tuple field expression access a tuple field, we allocate a tuple id in
     /// [`InferenceContext`] and store the tuples substitution there. This map is the reverse of
     /// that which allows us to resolve a [`TupleFieldId`]s type.
-    pub tuple_field_access_types: FxHashMap<TupleId, Substitution>,
+    tuple_field_access_types: FxHashMap<TupleId, Substitution>,
     /// During inference this field is empty and [`InferenceContext::diagnostics`] is filled instead.
-    pub diagnostics: Vec<InferenceDiagnostic>,
-    pub type_of_expr: ArenaMap<ExprId, Ty>,
+    diagnostics: Vec<InferenceDiagnostic>,
+    pub(crate) type_of_expr: ArenaMap<ExprId, Ty>,
     /// For each pattern record the type it resolves to.
     ///
     /// **Note**: When a pattern type is resolved it may still contain
     /// unresolved or missing subpatterns or subpatterns of mismatched types.
-    pub type_of_pat: ArenaMap<PatId, Ty>,
-    pub type_of_binding: ArenaMap<BindingId, Ty>,
-    pub type_of_rpit: ArenaMap<ImplTraitIdx, Ty>,
-    /// Type of the result of `.into_iter()` on the for. `ExprId` is the one of the whole for loop.
-    pub type_of_for_iterator: FxHashMap<ExprId, Ty>,
+    pub(crate) type_of_pat: ArenaMap<PatId, Ty>,
+    pub(crate) type_of_binding: ArenaMap<BindingId, Ty>,
+    pub(crate) type_of_rpit: ArenaMap<ImplTraitIdx, Ty>,
     type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
     /// Whether there are any type-mismatching errors in the result.
     // FIXME: This isn't as useful as initially thought due to us falling back placeholders to
@@ -483,7 +481,7 @@ pub struct InferenceResult {
     // FIXME: Move this into `InferenceContext`
     standard_types: InternedStandardTypes,
     /// Stores the types which were implicitly dereferenced in pattern binding modes.
-    pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
+    pub(crate) pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
     /// Stores the binding mode (`ref` in `let ref x = 2`) of bindings.
     ///
     /// This one is tied to the `PatId` instead of `BindingId`, because in some rare cases, a binding in an
@@ -497,12 +495,12 @@ pub struct InferenceResult {
     /// }
     /// ```
     /// the first `rest` has implicit `ref` binding mode, but the second `rest` binding mode is `move`.
-    pub binding_modes: ArenaMap<PatId, BindingMode>,
-    pub expr_adjustments: FxHashMap<ExprId, Box<[Adjustment]>>,
+    pub(crate) binding_modes: ArenaMap<PatId, BindingMode>,
+    pub(crate) expr_adjustments: FxHashMap<ExprId, Box<[Adjustment]>>,
     pub(crate) closure_info: FxHashMap<ClosureId, (Vec<CapturedItem>, FnTrait)>,
     // FIXME: remove this field
     pub mutated_bindings_in_closure: FxHashSet<BindingId>,
-    pub coercion_casts: FxHashSet<ExprId>,
+    pub(crate) coercion_casts: FxHashSet<ExprId>,
 }
 
 impl InferenceResult {
@@ -566,6 +564,26 @@ impl InferenceResult {
     pub fn is_erroneous(&self) -> bool {
         self.has_errors && self.type_of_expr.iter().count() == 0
     }
+
+    pub fn diagnostics(&self) -> &[InferenceDiagnostic] {
+        &self.diagnostics
+    }
+
+    pub fn tuple_field_access_type(&self, id: TupleId) -> &Substitution {
+        &self.tuple_field_access_types[&id]
+    }
+
+    pub fn pat_adjustment(&self, id: PatId) -> Option<&[Ty]> {
+        self.pat_adjustments.get(&id).map(|it| &**it)
+    }
+
+    pub fn expr_adjustment(&self, id: ExprId) -> Option<&[Adjustment]> {
+        self.expr_adjustments.get(&id).map(|it| &**it)
+    }
+
+    pub fn binding_mode(&self, id: PatId) -> Option<BindingMode> {
+        self.binding_modes.get(id).copied()
+    }
 }
 
 impl Index<ExprId> for InferenceResult {
@@ -772,7 +790,6 @@ impl<'db> InferenceContext<'db> {
             type_of_pat,
             type_of_binding,
             type_of_rpit,
-            type_of_for_iterator,
             type_mismatches,
             has_errors,
             standard_types: _,
@@ -832,11 +849,6 @@ impl<'db> InferenceContext<'db> {
             *has_errors = *has_errors || ty.contains_unknown();
         }
         type_of_rpit.shrink_to_fit();
-        for ty in type_of_for_iterator.values_mut() {
-            *ty = table.resolve_completely(ty.clone());
-            *has_errors = *has_errors || ty.contains_unknown();
-        }
-        type_of_for_iterator.shrink_to_fit();
 
         *has_errors |= !type_mismatches.is_empty();
 
@@ -1813,7 +1825,7 @@ impl<'db> InferenceContext<'db> {
     }
 
     fn resolve_output_on(&self, trait_: TraitId) -> Option<TypeAliasId> {
-        self.db.trait_items(trait_).associated_type_by_name(&Name::new_symbol_root(sym::Output))
+        trait_.trait_items(self.db).associated_type_by_name(&Name::new_symbol_root(sym::Output))
     }
 
     fn resolve_lang_trait(&self, lang: LangItem) -> Option<TraitId> {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs
index 8d345defdc1..4e95eca3f94 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs
@@ -382,7 +382,7 @@ fn pointer_kind(ty: &Ty, table: &mut InferenceTable<'_>) -> Result<Option<Pointe
                 return Err(());
             };
 
-            let struct_data = table.db.variant_fields(id.into());
+            let struct_data = id.fields(table.db);
             if let Some((last_field, _)) = struct_data.fields().iter().last() {
                 let last_field_ty =
                     table.db.field_types(id.into())[last_field].clone().substitute(Interner, subst);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
index b756bb859d3..c3029bf2b59 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
@@ -677,7 +677,7 @@ impl CapturedItem {
             match proj {
                 ProjectionElem::Deref => {}
                 ProjectionElem::Field(Either::Left(f)) => {
-                    let variant_data = f.parent.variant_data(db);
+                    let variant_data = f.parent.fields(db);
                     match variant_data.shape {
                         FieldsShape::Record => {
                             result.push('_');
@@ -720,7 +720,7 @@ impl CapturedItem {
                 // In source code autoderef kicks in.
                 ProjectionElem::Deref => {}
                 ProjectionElem::Field(Either::Left(f)) => {
-                    let variant_data = f.parent.variant_data(db);
+                    let variant_data = f.parent.fields(db);
                     match variant_data.shape {
                         FieldsShape::Record => format_to!(
                             result,
@@ -782,7 +782,7 @@ impl CapturedItem {
                     if field_need_paren {
                         result = format!("({result})");
                     }
-                    let variant_data = f.parent.variant_data(db);
+                    let variant_data = f.parent.fields(db);
                     let field = match variant_data.shape {
                         FieldsShape::Record => {
                             variant_data.fields()[f.local_id].name.as_str().to_owned()
@@ -1210,9 +1210,8 @@ impl InferenceContext<'_> {
                         if let Some(deref_trait) =
                             self.resolve_lang_item(LangItem::DerefMut).and_then(|it| it.as_trait())
                         {
-                            if let Some(deref_fn) = self
-                                .db
-                                .trait_items(deref_trait)
+                            if let Some(deref_fn) = deref_trait
+                                .trait_items(self.db)
                                 .method_by_name(&Name::new_symbol_root(sym::deref_mut))
                             {
                                 break 'b deref_fn == f;
@@ -1230,10 +1229,11 @@ impl InferenceContext<'_> {
                     self.select_from_expr(*expr);
                 }
             }
-            Expr::Let { pat: _, expr } => {
+            Expr::Let { pat, expr } => {
                 self.walk_expr(*expr);
-                let place = self.place_of_expr(*expr);
-                self.ref_expr(*expr, place);
+                if let Some(place) = self.place_of_expr(*expr) {
+                    self.consume_with_pat(place, *pat);
+                }
             }
             Expr::UnaryOp { expr, op: _ }
             | Expr::Array(Array::Repeat { initializer: expr, repeat: _ })
@@ -1560,7 +1560,7 @@ impl InferenceContext<'_> {
                             self.consume_place(place)
                         }
                         VariantId::StructId(s) => {
-                            let vd = &*self.db.variant_fields(s.into());
+                            let vd = s.fields(self.db);
                             for field_pat in args.iter() {
                                 let arg = field_pat.pat;
                                 let Some(local_id) = vd.field(&field_pat.name) else {
@@ -1612,7 +1612,7 @@ impl InferenceContext<'_> {
                             self.consume_place(place)
                         }
                         VariantId::StructId(s) => {
-                            let vd = &*self.db.variant_fields(s.into());
+                            let vd = s.fields(self.db);
                             let (al, ar) =
                                 args.split_at(ellipsis.map_or(args.len(), |it| it as usize));
                             let fields = vd.fields().iter();
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index 64031279296..d43c99fc282 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -542,7 +542,7 @@ impl InferenceContext<'_> {
                     _ if fields.is_empty() => {}
                     Some(def) => {
                         let field_types = self.db.field_types(def);
-                        let variant_data = def.variant_data(self.db);
+                        let variant_data = def.fields(self.db);
                         let visibilities = self.db.field_visibilities(def);
                         for field in fields.iter() {
                             let field_def = {
@@ -654,9 +654,8 @@ impl InferenceContext<'_> {
                 match op {
                     UnaryOp::Deref => {
                         if let Some(deref_trait) = self.resolve_lang_trait(LangItem::Deref) {
-                            if let Some(deref_fn) = self
-                                .db
-                                .trait_items(deref_trait)
+                            if let Some(deref_fn) = deref_trait
+                                .trait_items(self.db)
                                 .method_by_name(&Name::new_symbol_root(sym::deref))
                             {
                                 // FIXME: this is wrong in multiple ways, subst is empty, and we emit it even for builtin deref (note that
@@ -732,9 +731,32 @@ impl InferenceContext<'_> {
                     &Pat::Expr(expr) => {
                         Some(self.infer_expr(expr, &Expectation::none(), ExprIsRead::No))
                     }
-                    Pat::Path(path) => Some(self.infer_expr_path(path, target.into(), tgt_expr)),
+                    Pat::Path(path) => {
+                        let resolver_guard =
+                            self.resolver.update_to_inner_scope(self.db, self.owner, tgt_expr);
+                        let resolution = self.resolver.resolve_path_in_value_ns_fully(
+                            self.db,
+                            path,
+                            self.body.pat_path_hygiene(target),
+                        );
+                        self.resolver.reset_to_guard(resolver_guard);
+
+                        if matches!(
+                            resolution,
+                            Some(
+                                ValueNs::ConstId(_)
+                                    | ValueNs::StructId(_)
+                                    | ValueNs::EnumVariantId(_)
+                            )
+                        ) {
+                            None
+                        } else {
+                            Some(self.infer_expr_path(path, target.into(), tgt_expr))
+                        }
+                    }
                     _ => None,
                 };
+                let is_destructuring_assignment = lhs_ty.is_none();
 
                 if let Some(lhs_ty) = lhs_ty {
                     self.write_pat_ty(target, lhs_ty.clone());
@@ -748,7 +770,15 @@ impl InferenceContext<'_> {
                     self.inside_assignment = false;
                     self.resolver.reset_to_guard(resolver_guard);
                 }
-                self.result.standard_types.unit.clone()
+                if is_destructuring_assignment && self.diverges.is_always() {
+                    // Ordinary assignments always return `()`, even when they diverge.
+                    // However, rustc lowers destructuring assignments into blocks, and blocks return `!` if they have no tail
+                    // expression and they diverge. Therefore, we have to do the same here, even though we don't lower destructuring
+                    // assignments into blocks.
+                    self.table.new_maybe_never_var()
+                } else {
+                    self.result.standard_types.unit.clone()
+                }
             }
             Expr::Range { lhs, rhs, range_type } => {
                 let lhs_ty =
@@ -813,9 +843,8 @@ impl InferenceContext<'_> {
                         self.table.new_lifetime_var(),
                     ));
                     self.write_expr_adj(*base, adj.into_boxed_slice());
-                    if let Some(func) = self
-                        .db
-                        .trait_items(index_trait)
+                    if let Some(func) = index_trait
+                        .trait_items(self.db)
                         .method_by_name(&Name::new_symbol_root(sym::index))
                     {
                         let subst = TyBuilder::subst_for_def(self.db, index_trait, None);
@@ -1148,7 +1177,7 @@ impl InferenceContext<'_> {
         let Some(trait_) = fn_x.get_id(self.db, self.table.trait_env.krate) else {
             return;
         };
-        let trait_data = self.db.trait_items(trait_);
+        let trait_data = trait_.trait_items(self.db);
         if let Some(func) = trait_data.method_by_name(&fn_x.method_name()) {
             let subst = TyBuilder::subst_for_def(self.db, trait_, None)
                 .push(callee_ty.clone())
@@ -1316,7 +1345,7 @@ impl InferenceContext<'_> {
 
         let trait_func = lang_items_for_bin_op(op).and_then(|(name, lang_item)| {
             let trait_id = self.resolve_lang_item(lang_item)?.as_trait()?;
-            let func = self.db.trait_items(trait_id).method_by_name(&name)?;
+            let func = trait_id.trait_items(self.db).method_by_name(&name)?;
             Some((trait_id, func))
         });
         let (trait_, func) = match trait_func {
@@ -1568,12 +1597,12 @@ impl InferenceContext<'_> {
                     });
                 }
                 &TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), ref parameters) => {
-                    let local_id = self.db.variant_fields(s.into()).field(name)?;
+                    let local_id = s.fields(self.db).field(name)?;
                     let field = FieldId { parent: s.into(), local_id };
                     (field, parameters.clone())
                 }
                 &TyKind::Adt(AdtId(hir_def::AdtId::UnionId(u)), ref parameters) => {
-                    let local_id = self.db.variant_fields(u.into()).field(name)?;
+                    let local_id = u.fields(self.db).field(name)?;
                     let field = FieldId { parent: u.into(), local_id };
                     (field, parameters.clone())
                 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
index ac450c0b559..d2eaf212365 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
@@ -129,9 +129,8 @@ impl InferenceContext<'_> {
                         if let Some(index_trait) =
                             LangItem::IndexMut.resolve_trait(self.db, self.table.trait_env.krate)
                         {
-                            if let Some(index_fn) = self
-                                .db
-                                .trait_items(index_trait)
+                            if let Some(index_fn) = index_trait
+                                .trait_items(self.db)
                                 .method_by_name(&Name::new_symbol_root(sym::index_mut))
                             {
                                 *f = index_fn;
@@ -194,9 +193,8 @@ impl InferenceContext<'_> {
                             });
                             if is_mut_ptr {
                                 mutability = Mutability::Not;
-                            } else if let Some(deref_fn) = self
-                                .db
-                                .trait_items(deref_trait)
+                            } else if let Some(deref_fn) = deref_trait
+                                .trait_items(self.db)
                                 .method_by_name(&Name::new_symbol_root(sym::deref_mut))
                             {
                                 *f = deref_fn;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
index 4bc3e167ebf..99d3b5c7a84 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
@@ -38,7 +38,7 @@ impl InferenceContext<'_> {
         decl: Option<DeclContext>,
     ) -> Ty {
         let (ty, def) = self.resolve_variant(id.into(), path, true);
-        let var_data = def.map(|it| it.variant_data(self.db));
+        let var_data = def.map(|it| it.fields(self.db));
         if let Some(variant) = def {
             self.write_variant_resolution(id.into(), variant);
         }
@@ -60,7 +60,7 @@ impl InferenceContext<'_> {
             _ if subs.is_empty() => {}
             Some(def) => {
                 let field_types = self.db.field_types(def);
-                let variant_data = def.variant_data(self.db);
+                let variant_data = def.fields(self.db);
                 let visibilities = self.db.field_visibilities(def);
 
                 let (pre, post) = match ellipsis {
@@ -129,7 +129,7 @@ impl InferenceContext<'_> {
             _ if subs.len() == 0 => {}
             Some(def) => {
                 let field_types = self.db.field_types(def);
-                let variant_data = def.variant_data(self.db);
+                let variant_data = def.fields(self.db);
                 let visibilities = self.db.field_visibilities(def);
 
                 let substs = ty.as_adt().map(TupleExt::tail);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
index c327c13b664..bc8648ecdd9 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
@@ -278,7 +278,7 @@ impl InferenceContext<'_> {
     ) -> Option<(ValueNs, Substitution)> {
         let trait_ = trait_ref.hir_trait_id();
         let item =
-            self.db.trait_items(trait_).items.iter().map(|(_name, id)| *id).find_map(|item| {
+            trait_.trait_items(self.db).items.iter().map(|(_name, id)| *id).find_map(|item| {
                 match item {
                     AssocItemId::FunctionId(func) => {
                         if segment.name == &self.db.function_signature(func).name {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
index 631b571465f..c07755535f2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
@@ -859,7 +859,7 @@ impl<'a> InferenceTable<'a> {
         ] {
             let krate = self.trait_env.krate;
             let fn_trait = fn_trait_name.get_id(self.db, krate)?;
-            let trait_data = self.db.trait_items(fn_trait);
+            let trait_data = fn_trait.trait_items(self.db);
             let output_assoc_type =
                 trait_data.associated_type_by_name(&Name::new_symbol_root(output_assoc_name))?;
 
@@ -1001,7 +1001,7 @@ impl<'a> InferenceTable<'a> {
             // Must use a loop here and not recursion because otherwise users will conduct completely
             // artificial examples of structs that have themselves as the tail field and complain r-a crashes.
             while let Some((AdtId::StructId(id), subst)) = ty.as_adt() {
-                let struct_data = self.db.variant_fields(id.into());
+                let struct_data = id.fields(self.db);
                 if let Some((last_field, _)) = struct_data.fields().iter().next_back() {
                     let last_field_ty = self.db.field_types(id.into())[last_field]
                         .clone()
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
index 79a99321f10..b16b6a11784 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
@@ -132,7 +132,7 @@ impl UninhabitedFrom<'_> {
         variant: VariantId,
         subst: &Substitution,
     ) -> ControlFlow<VisiblyUninhabited> {
-        let variant_data = self.db.variant_fields(variant);
+        let variant_data = variant.fields(self.db);
         let fields = variant_data.fields();
         if fields.is_empty() {
             return CONTINUE_OPAQUELY_INHABITED;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
index c58bd1b773e..107da6a5af6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -261,7 +261,7 @@ pub fn layout_of_ty_query(
         }
         // Potentially-wide pointers.
         TyKind::Ref(_, _, pointee) | TyKind::Raw(_, pointee) => {
-            let mut data_ptr = scalar_unit(dl, Primitive::Pointer(AddressSpace::DATA));
+            let mut data_ptr = scalar_unit(dl, Primitive::Pointer(AddressSpace::ZERO));
             if matches!(ty.kind(Interner), TyKind::Ref(..)) {
                 data_ptr.valid_range_mut().start = 1;
             }
@@ -285,7 +285,7 @@ pub fn layout_of_ty_query(
                     scalar_unit(dl, Primitive::Int(dl.ptr_sized_integer(), false))
                 }
                 TyKind::Dyn(..) => {
-                    let mut vtable = scalar_unit(dl, Primitive::Pointer(AddressSpace::DATA));
+                    let mut vtable = scalar_unit(dl, Primitive::Pointer(AddressSpace::ZERO));
                     vtable.valid_range_mut().start = 1;
                     vtable
                 }
@@ -375,7 +375,7 @@ pub(crate) fn layout_of_ty_cycle_result(
 fn struct_tail_erasing_lifetimes(db: &dyn HirDatabase, pointee: Ty) -> Ty {
     match pointee.kind(Interner) {
         &TyKind::Adt(AdtId(hir_def::AdtId::StructId(i)), ref subst) => {
-            let data = db.variant_fields(i.into());
+            let data = i.fields(db);
             let mut it = data.fields().iter().rev();
             match it.next() {
                 Some((f, _)) => {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
index dff986fec3c..236f316366d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
@@ -42,7 +42,7 @@ pub fn layout_of_adt_query(
         AdtId::StructId(s) => {
             let sig = db.struct_signature(s);
             let mut r = SmallVec::<[_; 1]>::new();
-            r.push(handle_variant(s.into(), &db.variant_fields(s.into()))?);
+            r.push(handle_variant(s.into(), s.fields(db))?);
             (
                 r,
                 sig.repr.unwrap_or_default(),
@@ -52,7 +52,7 @@ pub fn layout_of_adt_query(
         AdtId::UnionId(id) => {
             let data = db.union_signature(id);
             let mut r = SmallVec::new();
-            r.push(handle_variant(id.into(), &db.variant_fields(id.into()))?);
+            r.push(handle_variant(id.into(), id.fields(db))?);
             (r, data.repr.unwrap_or_default(), false)
         }
         AdtId::EnumId(e) => {
@@ -60,7 +60,7 @@ pub fn layout_of_adt_query(
             let r = variants
                 .variants
                 .iter()
-                .map(|&(v, _, _)| handle_variant(v.into(), &db.variant_fields(v.into())))
+                .map(|&(v, _, _)| handle_variant(v.into(), v.fields(db)))
                 .collect::<Result<SmallVec<_>, _>>()?;
             (r, db.enum_signature(e).repr.unwrap_or_default(), false)
         }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs
index e1e1c44996c..88c33ecccad 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs
@@ -2,7 +2,7 @@
 
 use base_db::Crate;
 use hir_def::layout::TargetDataLayout;
-use rustc_abi::{AlignFromBytesError, TargetDataLayoutErrors};
+use rustc_abi::{AlignFromBytesError, TargetDataLayoutErrors, AddressSpace};
 use triomphe::Arc;
 
 use crate::db::HirDatabase;
@@ -12,7 +12,7 @@ pub fn target_data_layout_query(
     krate: Crate,
 ) -> Result<Arc<TargetDataLayout>, Arc<str>> {
     match &krate.workspace_data(db).data_layout {
-        Ok(it) => match TargetDataLayout::parse_from_llvm_datalayout_string(it) {
+        Ok(it) => match TargetDataLayout::parse_from_llvm_datalayout_string(it, AddressSpace::ZERO) {
             Ok(it) => Ok(Arc::new(it)),
             Err(e) => {
                 Err(match e {
@@ -39,6 +39,7 @@ pub fn target_data_layout_query(
                         target,
                     } => format!(r#"inconsistent target specification: "data-layout" claims pointers are {pointer_size}-bit, while "target-pointer-width" is `{target}`"#),
                     TargetDataLayoutErrors::InvalidBitsSize { err } => err,
+                    TargetDataLayoutErrors::UnknownPointerSpecification { err } => format!(r#"use of unknown pointer specifer in "data-layout": {err}"#),
                 }.into())
             }
         },
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
index 148f2a41e7d..e787fd9b1e5 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -891,8 +891,8 @@ pub fn callable_sig_from_fn_trait(
 ) -> Option<(FnTrait, CallableSig)> {
     let krate = trait_env.krate;
     let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?;
-    let output_assoc_type = db
-        .trait_items(fn_once_trait)
+    let output_assoc_type = fn_once_trait
+        .trait_items(db)
         .associated_type_by_name(&Name::new_symbol_root(sym::Output))?;
 
     let mut table = InferenceTable::new(db, trait_env.clone());
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 0a546768dab..f32b6af4d85 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -581,11 +581,28 @@ impl<'a> TyLoweringContext<'a> {
         match bound {
             &TypeBound::Path(path, TraitBoundModifier::None) | &TypeBound::ForLifetime(_, path) => {
                 // FIXME Don't silently drop the hrtb lifetimes here
-                if let Some((trait_ref, ctx)) = self.lower_trait_ref_from_path(path, self_ty) {
-                    if !ignore_bindings {
-                        assoc_bounds = ctx.assoc_type_bindings_from_type_bound(trait_ref.clone());
+                if let Some((trait_ref, mut ctx)) =
+                    self.lower_trait_ref_from_path(path, self_ty.clone())
+                {
+                    // FIXME(sized-hierarchy): Remove this bound modifications once we have implemented
+                    // sized-hierarchy correctly.
+                    let meta_sized = LangItem::MetaSized
+                        .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate());
+                    let pointee_sized = LangItem::PointeeSized
+                        .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate());
+                    if meta_sized.is_some_and(|it| it == trait_ref.hir_trait_id()) {
+                        // Ignore this bound
+                    } else if pointee_sized.is_some_and(|it| it == trait_ref.hir_trait_id()) {
+                        // Regard this as `?Sized` bound
+                        ctx.ty_ctx().unsized_types.insert(self_ty);
+                    } else {
+                        if !ignore_bindings {
+                            assoc_bounds =
+                                ctx.assoc_type_bindings_from_type_bound(trait_ref.clone());
+                        }
+                        clause =
+                            Some(crate::wrap_empty_binders(WhereClause::Implemented(trait_ref)));
                     }
-                    clause = Some(crate::wrap_empty_binders(WhereClause::Implemented(trait_ref)));
                 }
             }
             &TypeBound::Path(path, TraitBoundModifier::Maybe) => {
@@ -711,7 +728,7 @@ impl<'a> TyLoweringContext<'a> {
                             .unwrap_or(it),
                         None => it,
                     },
-                    None => static_lifetime(),
+                    None => error_lifetime(),
                 },
             })
             .intern(Interner)
@@ -805,7 +822,7 @@ fn named_associated_type_shorthand_candidates<R>(
 ) -> Option<R> {
     let mut search = |t| {
         all_super_trait_refs(db, t, |t| {
-            let data = db.trait_items(t.hir_trait_id());
+            let data = t.hir_trait_id().trait_items(db);
 
             for (name, assoc_id) in &data.items {
                 if let AssocItemId::TypeAliasId(alias) = assoc_id {
@@ -883,7 +900,12 @@ pub(crate) fn field_types_with_diagnostics_query(
     db: &dyn HirDatabase,
     variant_id: VariantId,
 ) -> (Arc<ArenaMap<LocalFieldId, Binders<Ty>>>, Diagnostics) {
-    let var_data = db.variant_fields(variant_id);
+    let var_data = variant_id.fields(db);
+    let fields = var_data.fields();
+    if fields.is_empty() {
+        return (Arc::new(ArenaMap::default()), None);
+    }
+
     let (resolver, def): (_, GenericDefId) = match variant_id {
         VariantId::StructId(it) => (it.resolver(db), it.into()),
         VariantId::UnionId(it) => (it.resolver(db), it.into()),
@@ -899,7 +921,7 @@ pub(crate) fn field_types_with_diagnostics_query(
         LifetimeElisionKind::AnonymousReportError,
     )
     .with_type_param_mode(ParamLoweringMode::Variable);
-    for (field_id, field_data) in var_data.fields().iter() {
+    for (field_id, field_data) in fields.iter() {
         res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(field_data.type_ref)));
     }
     (Arc::new(res), create_diagnostics(ctx.diagnostics))
@@ -920,6 +942,10 @@ pub(crate) fn generic_predicates_for_param_query(
     assoc_name: Option<Name>,
 ) -> GenericPredicates {
     let generics = generics(db, def);
+    if generics.has_no_predicates() && generics.is_empty() {
+        return GenericPredicates(None);
+    }
+
     let resolver = def.resolver(db);
     let mut ctx = TyLoweringContext::new(
         db,
@@ -936,8 +962,32 @@ pub(crate) fn generic_predicates_for_param_query(
         | WherePredicate::TypeBound { target, bound, .. } => {
             let invalid_target = { ctx.lower_ty_only_param(*target) != Some(param_id) };
             if invalid_target {
-                // If this is filtered out without lowering, `?Sized` is not gathered into `ctx.unsized_types`
-                if let TypeBound::Path(_, TraitBoundModifier::Maybe) = bound {
+                // FIXME(sized-hierarchy): Revisit and adjust this properly once we have implemented
+                // sized-hierarchy correctly.
+                // If this is filtered out without lowering, `?Sized` or `PointeeSized` is not gathered into
+                // `ctx.unsized_types`
+                let lower = || -> bool {
+                    match bound {
+                        TypeBound::Path(_, TraitBoundModifier::Maybe) => true,
+                        TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
+                            let TypeRef::Path(path) = &ctx.store[path.type_ref()] else {
+                                return false;
+                            };
+                            let Some(pointee_sized) =
+                                LangItem::PointeeSized.resolve_trait(ctx.db, ctx.resolver.krate())
+                            else {
+                                return false;
+                            };
+                            // Lower the path directly with `Resolver` instead of PathLoweringContext`
+                            // to prevent diagnostics duplications.
+                            ctx.resolver.resolve_path_in_type_ns_fully(ctx.db, path).is_some_and(
+                                |it| matches!(it, TypeNs::TraitId(tr) if tr == pointee_sized),
+                            )
+                        }
+                        _ => false,
+                    }
+                }();
+                if lower {
                     ctx.lower_where_predicate(pred, true).for_each(drop);
                 }
                 return false;
@@ -957,7 +1007,7 @@ pub(crate) fn generic_predicates_for_param_query(
                     };
 
                     all_super_traits(db, tr).iter().any(|tr| {
-                        db.trait_items(*tr).items.iter().any(|(name, item)| {
+                        tr.trait_items(db).items.iter().any(|(name, item)| {
                             matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name
                         })
                     })
@@ -1025,6 +1075,10 @@ pub(crate) fn trait_environment_query(
     def: GenericDefId,
 ) -> Arc<TraitEnvironment> {
     let generics = generics(db, def);
+    if generics.has_no_predicates() && generics.is_empty() {
+        return TraitEnvironment::empty(def.krate(db));
+    }
+
     let resolver = def.resolver(db);
     let mut ctx = TyLoweringContext::new(
         db,
@@ -1128,6 +1182,10 @@ where
     F: Fn(&WherePredicate, GenericDefId) -> bool,
 {
     let generics = generics(db, def);
+    if generics.has_no_predicates() && generics.is_empty() {
+        return (GenericPredicates(None), None);
+    }
+
     let resolver = def.resolver(db);
     let mut ctx = TyLoweringContext::new(
         db,
@@ -1154,7 +1212,7 @@ where
         }
     }
 
-    if generics.len() > 0 {
+    if !generics.is_empty() {
         let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
         let explicitly_unsized_tys = ctx.unsized_types;
         if let Some(implicitly_sized_predicates) =
@@ -1229,7 +1287,7 @@ pub(crate) fn generic_defaults_with_diagnostics_query(
     def: GenericDefId,
 ) -> (GenericDefaults, Diagnostics) {
     let generic_params = generics(db, def);
-    if generic_params.len() == 0 {
+    if generic_params.is_empty() {
         return (GenericDefaults(None), None);
     }
     let resolver = def.resolver(db);
@@ -1418,7 +1476,7 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS
 
 /// Build the type of a tuple struct constructor.
 fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Option<Binders<Ty>> {
-    let struct_data = db.variant_fields(def.into());
+    let struct_data = def.fields(db);
     match struct_data.shape {
         FieldsShape::Record => None,
         FieldsShape::Unit => Some(type_for_adt(db, def.into())),
@@ -1451,7 +1509,7 @@ fn type_for_enum_variant_constructor(
     def: EnumVariantId,
 ) -> Option<Binders<Ty>> {
     let e = def.lookup(db).parent;
-    match db.variant_fields(def.into()).shape {
+    match def.fields(db).shape {
         FieldsShape::Record => None,
         FieldsShape::Unit => Some(type_for_adt(db, e.into())),
         FieldsShape::Tuple => {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs
index 726eaf8b0a1..06686b6a164 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs
@@ -173,7 +173,7 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
                         self.skip_resolved_segment();
                         let segment = self.current_or_prev_segment;
                         let found =
-                            self.ctx.db.trait_items(trait_).associated_type_by_name(segment.name);
+                            trait_.trait_items(self.ctx.db).associated_type_by_name(segment.name);
 
                         match found {
                             Some(associated_ty) => {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs
index 6936d8193eb..9d3d2044c43 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs
@@ -13,7 +13,8 @@ use salsa::{
 
 use crate::{
     AssocTypeId, CallableDefId, ChalkTraitId, FnDefId, ForeignDefId, Interner, OpaqueTyId,
-    PlaceholderIndex, chalk_db, db::HirDatabase,
+    PlaceholderIndex, chalk_db,
+    db::{HirDatabase, InternedLifetimeParamId, InternedTypeOrConstParamId},
 };
 
 pub trait ToChalk {
@@ -125,30 +126,32 @@ pub fn from_assoc_type_id(id: AssocTypeId) -> TypeAliasId {
 pub fn from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> TypeOrConstParamId {
     assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT);
     // SAFETY: We cannot really encapsulate this unfortunately, so just hope this is sound.
-    let interned_id = FromId::from_id(unsafe { Id::from_u32(idx.idx.try_into().unwrap()) });
-    db.lookup_intern_type_or_const_param_id(interned_id)
+    let interned_id =
+        InternedTypeOrConstParamId::from_id(unsafe { Id::from_index(idx.idx.try_into().unwrap()) });
+    interned_id.loc(db)
 }
 
 pub fn to_placeholder_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> PlaceholderIndex {
-    let interned_id = db.intern_type_or_const_param_id(id);
+    let interned_id = InternedTypeOrConstParamId::new(db, id);
     PlaceholderIndex {
         ui: chalk_ir::UniverseIndex::ROOT,
-        idx: interned_id.as_id().as_u32() as usize,
+        idx: interned_id.as_id().index() as usize,
     }
 }
 
 pub fn lt_from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> LifetimeParamId {
     assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT);
     // SAFETY: We cannot really encapsulate this unfortunately, so just hope this is sound.
-    let interned_id = FromId::from_id(unsafe { Id::from_u32(idx.idx.try_into().unwrap()) });
-    db.lookup_intern_lifetime_param_id(interned_id)
+    let interned_id =
+        InternedLifetimeParamId::from_id(unsafe { Id::from_index(idx.idx.try_into().unwrap()) });
+    interned_id.loc(db)
 }
 
 pub fn lt_to_placeholder_idx(db: &dyn HirDatabase, id: LifetimeParamId) -> PlaceholderIndex {
-    let interned_id = db.intern_lifetime_param_id(id);
+    let interned_id = InternedLifetimeParamId::new(db, id);
     PlaceholderIndex {
         ui: chalk_ir::UniverseIndex::ROOT,
-        idx: interned_id.as_id().as_u32() as usize,
+        idx: interned_id.as_id().index() as usize,
     }
 }
 
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 25f1782bdd8..a6150a9bc17 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
@@ -1302,7 +1302,7 @@ fn iterate_trait_method_candidates(
         // trait, but if we find out it doesn't, we'll skip the rest of the
         // iteration
         let mut known_implemented = false;
-        for &(_, item) in db.trait_items(t).items.iter() {
+        for &(_, item) in t.trait_items(db).items.iter() {
             // Don't pass a `visible_from_module` down to `is_valid_candidate`,
             // since only inherent methods should be included into visibility checking.
             let visible =
@@ -1429,7 +1429,7 @@ fn iterate_inherent_methods(
     ) -> ControlFlow<()> {
         let db = table.db;
         for t in traits {
-            let data = db.trait_items(t);
+            let data = t.trait_items(db);
             for &(_, item) in data.items.iter() {
                 // We don't pass `visible_from_module` as all trait items should be visible.
                 let visible = match is_valid_trait_method_candidate(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
index a8156ec375b..55fada14363 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
@@ -630,7 +630,7 @@ impl Evaluator<'_> {
             Ok(target_data_layout) => target_data_layout,
             Err(e) => return Err(MirEvalError::TargetDataLayoutNotAvailable(e)),
         };
-        let cached_ptr_size = target_data_layout.pointer_size.bytes_usize();
+        let cached_ptr_size = target_data_layout.pointer_size().bytes_usize();
         Ok(Evaluator {
             target_data_layout,
             stack: vec![0],
@@ -657,12 +657,12 @@ impl Evaluator<'_> {
             cached_ptr_size,
             cached_fn_trait_func: LangItem::Fn
                 .resolve_trait(db, crate_id)
-                .and_then(|x| db.trait_items(x).method_by_name(&Name::new_symbol_root(sym::call))),
+                .and_then(|x| x.trait_items(db).method_by_name(&Name::new_symbol_root(sym::call))),
             cached_fn_mut_trait_func: LangItem::FnMut.resolve_trait(db, crate_id).and_then(|x| {
-                db.trait_items(x).method_by_name(&Name::new_symbol_root(sym::call_mut))
+                x.trait_items(db).method_by_name(&Name::new_symbol_root(sym::call_mut))
             }),
             cached_fn_once_trait_func: LangItem::FnOnce.resolve_trait(db, crate_id).and_then(|x| {
-                db.trait_items(x).method_by_name(&Name::new_symbol_root(sym::call_once))
+                x.trait_items(db).method_by_name(&Name::new_symbol_root(sym::call_once))
             }),
         })
     }
@@ -1749,8 +1749,7 @@ impl Evaluator<'_> {
                         AdtId::UnionId(_) => not_supported!("unsizing unions"),
                         AdtId::EnumId(_) => not_supported!("unsizing enums"),
                     };
-                    let Some((last_field, _)) =
-                        self.db.variant_fields(id.into()).fields().iter().next_back()
+                    let Some((last_field, _)) = id.fields(self.db).fields().iter().next_back()
                     else {
                         not_supported!("unsizing struct without field");
                     };
@@ -2232,7 +2231,7 @@ impl Evaluator<'_> {
                 }
                 chalk_ir::TyKind::Adt(adt, subst) => match adt.0 {
                     AdtId::StructId(s) => {
-                        let data = this.db.variant_fields(s.into());
+                        let data = s.fields(this.db);
                         let layout = this.layout(ty)?;
                         let field_types = this.db.field_types(s.into());
                         for (f, _) in data.fields().iter() {
@@ -2261,7 +2260,7 @@ impl Evaluator<'_> {
                             bytes,
                             e,
                         ) {
-                            let data = &this.db.variant_fields(v.into());
+                            let data = v.fields(this.db);
                             let field_types = this.db.field_types(v.into());
                             for (f, _) in data.fields().iter() {
                                 let offset =
@@ -2808,7 +2807,7 @@ impl Evaluator<'_> {
     ) -> Result<()> {
         let Some(drop_fn) = (|| {
             let drop_trait = LangItem::Drop.resolve_trait(self.db, self.crate_id)?;
-            self.db.trait_items(drop_trait).method_by_name(&Name::new_symbol_root(sym::drop))
+            drop_trait.trait_items(self.db).method_by_name(&Name::new_symbol_root(sym::drop))
         })() else {
             // in some tests we don't have drop trait in minicore, and
             // we can ignore drop in them.
@@ -2838,7 +2837,7 @@ impl Evaluator<'_> {
                             return Ok(());
                         }
                         let layout = self.layout_adt(id.0, subst.clone())?;
-                        let variant_fields = self.db.variant_fields(s.into());
+                        let variant_fields = s.fields(self.db);
                         match variant_fields.shape {
                             FieldsShape::Record | FieldsShape::Tuple => {
                                 let field_types = self.db.field_types(s.into());
@@ -2918,7 +2917,7 @@ pub fn render_const_using_debug_impl(
         not_supported!("core::fmt::Debug not found");
     };
     let Some(debug_fmt_fn) =
-        db.trait_items(debug_trait).method_by_name(&Name::new_symbol_root(sym::fmt))
+        debug_trait.trait_items(db).method_by_name(&Name::new_symbol_root(sym::fmt))
     else {
         not_supported!("core::fmt::Debug::fmt not found");
     };
@@ -3045,7 +3044,10 @@ impl IntValue {
             (8, true) => Self::I64(i64::from_le_bytes(bytes.try_into().unwrap())),
             (16, false) => Self::U128(u128::from_le_bytes(bytes.try_into().unwrap())),
             (16, true) => Self::I128(i128::from_le_bytes(bytes.try_into().unwrap())),
-            _ => panic!("invalid integer size"),
+            (len, is_signed) => {
+                never!("invalid integer size: {len}, signed: {is_signed}");
+                Self::I32(0)
+            }
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
index 6ebde013344..e9665d5ae9c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
@@ -1257,9 +1257,8 @@ impl Evaluator<'_> {
                     args.push(IntervalAndTy::new(addr, field, self, locals)?);
                 }
                 if let Some(target) = LangItem::FnOnce.resolve_trait(self.db, self.crate_id) {
-                    if let Some(def) = self
-                        .db
-                        .trait_items(target)
+                    if let Some(def) = target
+                        .trait_items(self.db)
                         .method_by_name(&Name::new_symbol_root(sym::call_once))
                     {
                         self.exec_fn_trait(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs
index 984648cfec3..bc331a23d98 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs
@@ -31,7 +31,7 @@ impl Evaluator<'_> {
                     Some(len) => len,
                     _ => {
                         if let AdtId::StructId(id) = id.0 {
-                            let struct_data = self.db.variant_fields(id.into());
+                            let struct_data = id.fields(self.db);
                             let fields = struct_data.fields();
                             let Some((first_field, _)) = fields.iter().next() else {
                                 not_supported!("simd type with no field");
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 3abbbe45e6f..c1f86960e15 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
@@ -984,3 +984,17 @@ fn main<'a, T: Foo + Bar + Baz>(
         |e| matches!(e, MirEvalError::MirLowerError(_, MirLowerError::GenericArgNotProvided(..))),
     );
 }
+
+#[test]
+fn format_args_pass() {
+    check_pass(
+        r#"
+//- minicore: fmt
+fn main() {
+    let x1 = format_args!("");
+    let x2 = format_args!("{}", x1);
+    let x3 = format_args!("{} {}", x1, x2);
+}
+"#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
index 71e038b92f0..845d6b8eae1 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
@@ -503,7 +503,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                         Ok(Some(current))
                     }
                     ValueNs::EnumVariantId(variant_id) => {
-                        let variant_fields = &self.db.variant_fields(variant_id.into());
+                        let variant_fields = variant_id.fields(self.db);
                         if variant_fields.shape == FieldsShape::Unit {
                             let ty = self.infer.type_of_expr[expr_id].clone();
                             current = self.lower_enum_variant(
@@ -856,7 +856,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                     TyKind::Adt(_, s) => s.clone(),
                     _ => not_supported!("Non ADT record literal"),
                 };
-                let variant_fields = self.db.variant_fields(variant_id);
+                let variant_fields = variant_id.fields(self.db);
                 match variant_id {
                     VariantId::EnumVariantId(_) | VariantId::StructId(_) => {
                         let mut operands = vec![None; variant_fields.fields().len()];
@@ -1176,8 +1176,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                     place,
                     Rvalue::Aggregate(
                         AggregateKind::Adt(st.into(), subst.clone()),
-                        self.db
-                            .variant_fields(st.into())
+                        st.fields(self.db)
                             .fields()
                             .iter()
                             .map(|it| {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
index ad664693e29..e7bffead931 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
@@ -193,9 +193,8 @@ impl MirLowerCtx<'_> {
                                 if let Some(deref_trait) =
                                     self.resolve_lang_item(LangItem::DerefMut)?.as_trait()
                                 {
-                                    if let Some(deref_fn) = self
-                                        .db
-                                        .trait_items(deref_trait)
+                                    if let Some(deref_fn) = deref_trait
+                                        .trait_items(self.db)
                                         .method_by_name(&Name::new_symbol_root(sym::deref_mut))
                                     {
                                         break 'b deref_fn == f;
@@ -347,9 +346,8 @@ impl MirLowerCtx<'_> {
             .resolve_lang_item(trait_lang_item)?
             .as_trait()
             .ok_or(MirLowerError::LangItemNotFound(trait_lang_item))?;
-        let deref_fn = self
-            .db
-            .trait_items(deref_trait)
+        let deref_fn = deref_trait
+            .trait_items(self.db)
             .method_by_name(&trait_method_name)
             .ok_or(MirLowerError::LangItemNotFound(trait_lang_item))?;
         let deref_fn_op = Operand::const_zst(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
index b3c1f6f387f..61c0685c48a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
@@ -609,7 +609,7 @@ impl MirLowerCtx<'_> {
                 }
                 self.pattern_matching_variant_fields(
                     shape,
-                    &self.db.variant_fields(v.into()),
+                    v.fields(self.db),
                     variant,
                     current,
                     current_else,
@@ -619,7 +619,7 @@ impl MirLowerCtx<'_> {
             }
             VariantId::StructId(s) => self.pattern_matching_variant_fields(
                 shape,
-                &self.db.variant_fields(s.into()),
+                s.fields(self.db),
                 variant,
                 current,
                 current_else,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
index 8764e48b538..78a69cf4509 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
@@ -326,7 +326,7 @@ impl<'a> MirPrettyCtx<'a> {
                     w!(this, ")");
                 }
                 ProjectionElem::Field(Either::Left(field)) => {
-                    let variant_fields = this.db.variant_fields(field.parent);
+                    let variant_fields = field.parent.fields(this.db);
                     let name = &variant_fields.fields()[field.local_id].name;
                     match field.parent {
                         hir_def::VariantId::EnumVariantId(e) => {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
index d049c678e2d..b5de0e52f5b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
@@ -166,10 +166,10 @@ impl TestDB {
         self.events.lock().unwrap().take().unwrap()
     }
 
-    pub(crate) fn log_executed(&self, f: impl FnOnce()) -> Vec<String> {
+    pub(crate) fn log_executed(&self, f: impl FnOnce()) -> (Vec<String>, Vec<salsa::Event>) {
         let events = self.log(f);
-        events
-            .into_iter()
+        let executed = events
+            .iter()
             .filter_map(|e| match e.kind {
                 // This is pretty horrible, but `Debug` is the only way to inspect
                 // QueryDescriptor at the moment.
@@ -181,6 +181,7 @@ impl TestDB {
                 }
                 _ => None,
             })
-            .collect()
+            .collect();
+        (executed, events)
     }
 }
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 9ca6ee476c6..79754bc8a09 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
@@ -486,7 +486,7 @@ pub(crate) fn visit_module(
                     });
                 }
                 ModuleDefId::TraitId(it) => {
-                    let trait_data = db.trait_items(it);
+                    let trait_data = it.trait_items(db);
                     for &(_, item) in trait_data.items.iter() {
                         match item {
                             AssocItemId::FunctionId(it) => cb(it.into()),
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 7fb981752de..dbc68eeba1e 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
@@ -446,7 +446,7 @@ fn main() {
 }
 
 #[test]
-fn let_binding_is_a_ref_capture() {
+fn let_binding_is_a_ref_capture_in_ref_binding() {
     check_closure_captures(
         r#"
 //- minicore:copy
@@ -454,12 +454,36 @@ struct S;
 fn main() {
     let mut s = S;
     let s_ref = &mut s;
+    let mut s2 = S;
+    let s_ref2 = &mut s2;
     let closure = || {
         if let ref cb = s_ref {
+        } else if let ref mut cb = s_ref2 {
         }
     };
 }
 "#,
-        expect!["83..135;49..54;112..117 ByRef(Shared) s_ref &'? &'? mut S"],
+        expect![[r#"
+            129..225;49..54;149..155 ByRef(Shared) s_ref &'? &'? mut S
+            129..225;93..99;188..198 ByRef(Mut { kind: Default }) s_ref2 &'? mut &'? mut S"#]],
+    );
+}
+
+#[test]
+fn let_binding_is_a_value_capture_in_binding() {
+    check_closure_captures(
+        r#"
+//- minicore:copy, option
+struct Box(i32);
+fn main() {
+    let b = Some(Box(0));
+    let closure = || {
+        if let Some(b) = b {
+            let _move = b;
+        }
+    };
+}
+"#,
+        expect!["73..149;37..38;103..104 ByValue b Option<Box>"],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
index ddc5b715194..3894b4b6f7b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
@@ -561,7 +561,7 @@ trait Foo {}
 fn test(f: impl Foo, g: &(impl Foo + ?Sized)) {
     let _: &dyn Foo = &f;
     let _: &dyn Foo = g;
-                    //^ expected &'? (dyn Foo + 'static), got &'? impl Foo + ?Sized
+                    //^ expected &'? (dyn Foo + '?), got &'? impl Foo + ?Sized
 }
         "#,
     );
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
index a986b54a7b0..6e3faa05a62 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
@@ -67,11 +67,11 @@ trait B: A {}
 
 fn test<'a>(
     _: &(dyn A<Assoc = ()> + Send),
-  //^ &(dyn A<Assoc = ()> + Send + 'static)
+  //^ &(dyn A<Assoc = ()> + Send)
     _: &'a (dyn Send + A<Assoc = ()>),
-  //^ &'a (dyn A<Assoc = ()> + Send + 'static)
+  //^ &'a (dyn A<Assoc = ()> + Send)
     _: &dyn B<Assoc = ()>,
-  //^ &(dyn B<Assoc = ()> + 'static)
+  //^ &(dyn B<Assoc = ()>)
 ) {}
         "#,
     );
@@ -85,7 +85,7 @@ fn render_dyn_for_ty() {
 trait Foo<'a> {}
 
 fn foo(foo: &dyn for<'a> Foo<'a>) {}
-    // ^^^ &(dyn Foo<'?> + 'static)
+    // ^^^ &dyn Foo<'?>
 "#,
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
index 905fd8a3bca..3159499e867 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
@@ -1,6 +1,7 @@
 use base_db::SourceDatabase;
 use expect_test::Expect;
 use hir_def::{DefWithBodyId, ModuleDefId};
+use salsa::EventKind;
 use test_fixture::WithFixture;
 
 use crate::{db::HirDatabase, test_db::TestDB};
@@ -567,11 +568,11 @@ fn main() {
                 "ast_id_map_shim",
                 "parse_shim",
                 "real_span_map_shim",
-                "trait_items_with_diagnostics_shim",
+                "TraitItems::query_with_diagnostics_",
                 "body_shim",
                 "body_with_source_map_shim",
                 "attrs_shim",
-                "of_",
+                "ImplItems::of_",
                 "infer_shim",
                 "trait_signature_shim",
                 "trait_signature_with_source_map_shim",
@@ -596,8 +597,8 @@ fn main() {
                 "struct_signature_with_source_map_shim",
                 "generic_predicates_shim",
                 "value_ty_shim",
-                "variant_fields_shim",
-                "variant_fields_with_source_map_shim",
+                "VariantFields::firewall_",
+                "VariantFields::query_",
                 "lang_item",
                 "inherent_impls_in_crate_shim",
                 "impl_signature_shim",
@@ -674,11 +675,11 @@ fn main() {
                 "file_item_tree_query",
                 "real_span_map_shim",
                 "crate_local_def_map",
-                "trait_items_with_diagnostics_shim",
+                "TraitItems::query_with_diagnostics_",
                 "body_with_source_map_shim",
                 "attrs_shim",
                 "body_shim",
-                "of_",
+                "ImplItems::of_",
                 "infer_shim",
                 "attrs_shim",
                 "trait_signature_with_source_map_shim",
@@ -695,11 +696,9 @@ fn main() {
                 "return_type_impl_traits_shim",
                 "infer_shim",
                 "function_signature_with_source_map_shim",
-                "trait_environment_shim",
                 "expr_scopes_shim",
                 "struct_signature_with_source_map_shim",
-                "generic_predicates_shim",
-                "variant_fields_with_source_map_shim",
+                "VariantFields::query_",
                 "inherent_impls_in_crate_shim",
                 "impl_signature_with_source_map_shim",
                 "impl_signature_shim",
@@ -709,7 +708,6 @@ fn main() {
                 "impl_trait_with_diagnostics_shim",
                 "impl_self_ty_with_diagnostics_shim",
                 "generic_predicates_shim",
-                "generic_predicates_shim",
             ]
         "#]],
     );
@@ -721,10 +719,23 @@ fn execute_assert_events(
     required: &[(&str, usize)],
     expect: Expect,
 ) {
-    let events = db.log_executed(f);
-    for (event, count) in required {
-        let n = events.iter().filter(|it| it.contains(event)).count();
-        assert_eq!(n, *count, "Expected {event} to be executed {count} times, but only got {n}");
-    }
-    expect.assert_debug_eq(&events);
+    let (executed, events) = db.log_executed(f);
+    salsa::attach(db, || {
+        for (event, count) in required {
+            let n = executed.iter().filter(|it| it.contains(event)).count();
+            assert_eq!(
+                n,
+                *count,
+                "Expected {event} to be executed {count} times, but only got {n}:\n \
+             Executed: {executed:#?}\n \
+             Event log: {events:#?}",
+                events = events
+                    .iter()
+                    .filter(|event| !matches!(event.kind, EventKind::WillCheckCancellation))
+                    .map(|event| { format!("{:?}", event.kind) })
+                    .collect::<Vec<_>>(),
+            );
+        }
+        expect.assert_debug_eq(&executed);
+    });
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
index 94826acca30..c58ca6c67a8 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
@@ -1153,9 +1153,9 @@ fn dyn_trait_super_trait_not_in_scope() {
             51..55 'self': &'? Self
             64..69 '{ 0 }': u32
             66..67 '0': u32
-            176..177 'd': &'? (dyn Trait + 'static)
+            176..177 'd': &'? (dyn Trait + '?)
             191..207 '{     ...o(); }': ()
-            197..198 'd': &'? (dyn Trait + 'static)
+            197..198 'd': &'? (dyn Trait + '?)
             197..204 'd.foo()': u32
         "#]],
     );
@@ -2019,10 +2019,10 @@ impl dyn Error + Send {
     /// Attempts to downcast the box to a concrete type.
     pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error + Send>> {
         let err: Box<dyn Error> = self;
-                               // ^^^^ expected Box<dyn Error + 'static>, got Box<dyn Error + Send + 'static>
+                               // ^^^^ expected Box<dyn Error + '?>, got Box<dyn Error + Send + '?>
                                // FIXME, type mismatch should not occur
         <dyn Error>::downcast(err).map_err(|_| loop {})
-      //^^^^^^^^^^^^^^^^^^^^^ type: fn downcast<{unknown}>(Box<dyn Error + 'static>) -> Result<Box<{unknown}>, Box<dyn Error + 'static>>
+      //^^^^^^^^^^^^^^^^^^^^^ type: fn downcast<{unknown}>(Box<dyn Error + '?>) -> Result<Box<{unknown}>, Box<dyn Error + '?>>
     }
 }
 "#,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs
index 1ca4c9b2ad5..6a9135622de 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs
@@ -785,3 +785,31 @@ fn make_up_a_pointer<T>() -> *const T {
         "#]],
     )
 }
+
+#[test]
+fn diverging_destructuring_assignment() {
+    check_infer_with_mismatches(
+        r#"
+fn foo() {
+    let n = match 42 {
+        0 => _ = loop {},
+        _ => 0,
+    };
+}
+    "#,
+        expect![[r#"
+            9..84 '{     ...  }; }': ()
+            19..20 'n': i32
+            23..81 'match ...     }': i32
+            29..31 '42': i32
+            42..43 '0': i32
+            42..43 '0': i32
+            47..48 '_': !
+            47..58 '_ = loop {}': i32
+            51..58 'loop {}': !
+            56..58 '{}': ()
+            68..69 '_': i32
+            73..74 '0': i32
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
index ff8adeef1db..238753e12e4 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
@@ -629,7 +629,7 @@ fn issue_4053_diesel_where_clauses() {
             488..522 '{     ...     }': ()
             498..502 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}>
             498..508 'self.order': O
-            498..515 'self.o...into()': dyn QueryFragment<DB> + 'static
+            498..515 'self.o...into()': dyn QueryFragment<DB> + '?
         "#]],
     );
 }
@@ -773,7 +773,7 @@ fn issue_4800() {
         "#,
         expect![[r#"
             379..383 'self': &'? mut PeerSet<D>
-            401..424 '{     ...     }': dyn Future<Output = ()> + 'static
+            401..424 '{     ...     }': dyn Future<Output = ()> + '?
             411..418 'loop {}': !
             416..418 '{}': ()
             575..579 'self': &'? mut Self
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 cf51671afb2..b154e598785 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
@@ -2741,11 +2741,11 @@ impl B for Astruct {}
             715..744 '#[rust...1i32])': Box<[i32; 1], Global>
             737..743 '[1i32]': [i32; 1]
             738..742 '1i32': i32
-            755..756 'v': Vec<Box<dyn B + 'static, Global>, Global>
-            776..793 '<[_]> ...to_vec': fn into_vec<Box<dyn B + 'static, Global>, Global>(Box<[Box<dyn B + 'static, Global>], Global>) -> Vec<Box<dyn B + 'static, Global>, Global>
-            776..850 '<[_]> ...ct)]))': Vec<Box<dyn B + 'static, Global>, Global>
-            794..849 '#[rust...uct)])': Box<[Box<dyn B + 'static, Global>; 1], Global>
-            816..848 '[#[rus...ruct)]': [Box<dyn B + 'static, Global>; 1]
+            755..756 'v': Vec<Box<dyn B + '?, Global>, Global>
+            776..793 '<[_]> ...to_vec': fn into_vec<Box<dyn B + '?, Global>, Global>(Box<[Box<dyn B + '?, Global>], Global>) -> Vec<Box<dyn B + '?, Global>, Global>
+            776..850 '<[_]> ...ct)]))': Vec<Box<dyn B + '?, Global>, Global>
+            794..849 '#[rust...uct)])': Box<[Box<dyn B + '?, Global>; 1], Global>
+            816..848 '[#[rus...ruct)]': [Box<dyn B + '?, Global>; 1]
             817..847 '#[rust...truct)': Box<Astruct, Global>
             839..846 'Astruct': Astruct
         "#]],
@@ -3751,7 +3751,7 @@ fn foo() {
     }
     let v: bool = true;
     m!();
- // ^^^^ i32
+ // ^^ i32
 }
         "#,
     );
@@ -3765,39 +3765,39 @@ fn foo() {
     let v: bool;
     macro_rules! m { () => { v } }
     m!();
- // ^^^^ bool
+ // ^^ bool
 
     let v: char;
     macro_rules! m { () => { v } }
     m!();
- // ^^^^ char
+ // ^^ char
 
     {
         let v: u8;
         macro_rules! m { () => { v } }
         m!();
-     // ^^^^ u8
+     // ^^ u8
 
         let v: i8;
         macro_rules! m { () => { v } }
         m!();
-     // ^^^^ i8
+     // ^^ i8
 
         let v: i16;
         macro_rules! m { () => { v } }
         m!();
-     // ^^^^ i16
+     // ^^ i16
 
         {
             let v: u32;
             macro_rules! m { () => { v } }
             m!();
-         // ^^^^ u32
+         // ^^ u32
 
             let v: u64;
             macro_rules! m { () => { v } }
             m!();
-         // ^^^^ u64
+         // ^^ u64
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index e5d1fbe9def..56e31a1af1b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -1475,26 +1475,26 @@ fn test(x: Box<dyn Trait<u64>>, y: &dyn Trait<u64>) {
         expect![[r#"
             29..33 'self': &'? Self
             54..58 'self': &'? Self
-            198..200 '{}': Box<dyn Trait<u64> + 'static>
-            210..211 'x': Box<dyn Trait<u64> + 'static>
-            234..235 'y': &'? (dyn Trait<u64> + 'static)
+            198..200 '{}': Box<dyn Trait<u64> + '?>
+            210..211 'x': Box<dyn Trait<u64> + '?>
+            234..235 'y': &'? (dyn Trait<u64> + '?)
             254..371 '{     ...2(); }': ()
-            260..261 'x': Box<dyn Trait<u64> + 'static>
-            267..268 'y': &'? (dyn Trait<u64> + 'static)
-            278..279 'z': Box<dyn Trait<u64> + 'static>
-            282..285 'bar': fn bar() -> Box<dyn Trait<u64> + 'static>
-            282..287 'bar()': Box<dyn Trait<u64> + 'static>
-            293..294 'x': Box<dyn Trait<u64> + 'static>
+            260..261 'x': Box<dyn Trait<u64> + '?>
+            267..268 'y': &'? (dyn Trait<u64> + '?)
+            278..279 'z': Box<dyn Trait<u64> + '?>
+            282..285 'bar': fn bar() -> Box<dyn Trait<u64> + '?>
+            282..287 'bar()': Box<dyn Trait<u64> + '?>
+            293..294 'x': Box<dyn Trait<u64> + '?>
             293..300 'x.foo()': u64
-            306..307 'y': &'? (dyn Trait<u64> + 'static)
+            306..307 'y': &'? (dyn Trait<u64> + '?)
             306..313 'y.foo()': u64
-            319..320 'z': Box<dyn Trait<u64> + 'static>
+            319..320 'z': Box<dyn Trait<u64> + '?>
             319..326 'z.foo()': u64
-            332..333 'x': Box<dyn Trait<u64> + 'static>
+            332..333 'x': Box<dyn Trait<u64> + '?>
             332..340 'x.foo2()': i64
-            346..347 'y': &'? (dyn Trait<u64> + 'static)
+            346..347 'y': &'? (dyn Trait<u64> + '?)
             346..354 'y.foo2()': i64
-            360..361 'z': Box<dyn Trait<u64> + 'static>
+            360..361 'z': Box<dyn Trait<u64> + '?>
             360..368 'z.foo2()': i64
         "#]],
     );
@@ -1523,14 +1523,14 @@ fn test(s: S<u32, i32>) {
         expect![[r#"
             32..36 'self': &'? Self
             102..106 'self': &'? S<T, U>
-            128..139 '{ loop {} }': &'? (dyn Trait<T, U> + 'static)
+            128..139 '{ loop {} }': &'? (dyn Trait<T, U> + '?)
             130..137 'loop {}': !
             135..137 '{}': ()
             175..179 'self': &'? Self
             251..252 's': S<u32, i32>
             267..289 '{     ...z(); }': ()
             273..274 's': S<u32, i32>
-            273..280 's.bar()': &'? (dyn Trait<u32, i32> + 'static)
+            273..280 's.bar()': &'? (dyn Trait<u32, i32> + '?)
             273..286 's.bar().baz()': (u32, i32)
         "#]],
     );
@@ -1556,20 +1556,20 @@ fn test(x: Trait, y: &Trait) -> u64 {
 }"#,
         expect![[r#"
             26..30 'self': &'? Self
-            60..62 '{}': dyn Trait + 'static
-            72..73 'x': dyn Trait + 'static
-            82..83 'y': &'? (dyn Trait + 'static)
+            60..62 '{}': dyn Trait + '?
+            72..73 'x': dyn Trait + '?
+            82..83 'y': &'? (dyn Trait + '?)
             100..175 '{     ...o(); }': u64
-            106..107 'x': dyn Trait + 'static
-            113..114 'y': &'? (dyn Trait + 'static)
-            124..125 'z': dyn Trait + 'static
-            128..131 'bar': fn bar() -> dyn Trait + 'static
-            128..133 'bar()': dyn Trait + 'static
-            139..140 'x': dyn Trait + 'static
+            106..107 'x': dyn Trait + '?
+            113..114 'y': &'? (dyn Trait + '?)
+            124..125 'z': dyn Trait + '?
+            128..131 'bar': fn bar() -> dyn Trait + '?
+            128..133 'bar()': dyn Trait + '?
+            139..140 'x': dyn Trait + '?
             139..146 'x.foo()': u64
-            152..153 'y': &'? (dyn Trait + 'static)
+            152..153 'y': &'? (dyn Trait + '?)
             152..159 'y.foo()': u64
-            165..166 'z': dyn Trait + 'static
+            165..166 'z': dyn Trait + '?
             165..172 'z.foo()': u64
         "#]],
     );
@@ -1589,10 +1589,10 @@ fn main() {
         expect![[r#"
             31..35 'self': &'? S
             37..39 '{}': ()
-            47..48 '_': &'? (dyn Fn(S) + 'static)
+            47..48 '_': &'? (dyn Fn(S) + '?)
             58..60 '{}': ()
             71..105 '{     ...()); }': ()
-            77..78 'f': fn f(&'? (dyn Fn(S) + 'static))
+            77..78 'f': fn f(&'? (dyn Fn(S) + '?))
             77..102 'f(&|nu...foo())': ()
             79..101 '&|numb....foo()': &'? impl Fn(S)
             80..101 '|numbe....foo()': impl Fn(S)
@@ -2927,13 +2927,13 @@ fn test(x: &dyn Foo) {
     foo(x);
 }"#,
         expect![[r#"
-            21..22 'x': &'? (dyn Foo + 'static)
+            21..22 'x': &'? (dyn Foo + '?)
             34..36 '{}': ()
-            46..47 'x': &'? (dyn Foo + 'static)
+            46..47 'x': &'? (dyn Foo + '?)
             59..74 '{     foo(x); }': ()
-            65..68 'foo': fn foo(&'? (dyn Foo + 'static))
+            65..68 'foo': fn foo(&'? (dyn Foo + '?))
             65..71 'foo(x)': ()
-            69..70 'x': &'? (dyn Foo + 'static)
+            69..70 'x': &'? (dyn Foo + '?)
         "#]],
     );
 }
@@ -3210,13 +3210,13 @@ fn foo() {
             218..324 '{     ...&s); }': ()
             228..229 's': Option<i32>
             232..236 'None': Option<i32>
-            246..247 'f': Box<dyn FnOnce(&'? Option<i32>) + 'static>
-            281..310 'Box { ... {}) }': Box<dyn FnOnce(&'? Option<i32>) + 'static>
+            246..247 'f': Box<dyn FnOnce(&'? Option<i32>) + '?>
+            281..310 'Box { ... {}) }': Box<dyn FnOnce(&'? Option<i32>) + '?>
             294..308 '&mut (|ps| {})': &'? mut impl FnOnce(&'? Option<i32>)
             300..307 '|ps| {}': impl FnOnce(&'? Option<i32>)
             301..303 'ps': &'? Option<i32>
             305..307 '{}': ()
-            316..317 'f': Box<dyn FnOnce(&'? Option<i32>) + 'static>
+            316..317 'f': Box<dyn FnOnce(&'? Option<i32>) + '?>
             316..321 'f(&s)': ()
             318..320 '&s': &'? Option<i32>
             319..320 's': Option<i32>
@@ -4252,9 +4252,9 @@ fn f<'a>(v: &dyn Trait<Assoc<i32> = &'a i32>) {
     "#,
         expect![[r#"
             90..94 'self': &'? Self
-            127..128 'v': &'? (dyn Trait<Assoc<i32> = &'a i32> + 'static)
+            127..128 'v': &'? (dyn Trait<Assoc<i32> = &'a i32> + '?)
             164..195 '{     ...f(); }': ()
-            170..171 'v': &'? (dyn Trait<Assoc<i32> = &'a i32> + 'static)
+            170..171 'v': &'? (dyn Trait<Assoc<i32> = &'a i32> + '?)
             170..184 'v.get::<i32>()': &'? i32
             170..192 'v.get:...eref()': &'? i32
         "#]],
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
index 4c8e635eff9..d07c1aa33b4 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
@@ -1,7 +1,7 @@
 //! Helper functions for working with def, which don't need to be a separate
 //! query, but can't be computed directly from `*Data` (ie, which need a `db`).
 
-use std::iter;
+use std::{cell::LazyCell, iter};
 
 use base_db::Crate;
 use chalk_ir::{
@@ -161,11 +161,12 @@ impl Iterator for ClauseElaborator<'_> {
 }
 
 fn direct_super_traits_cb(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) {
-    let resolver = trait_.resolver(db);
+    let resolver = LazyCell::new(|| trait_.resolver(db));
     let (generic_params, store) = db.generic_params_and_store(trait_.into());
     let trait_self = generic_params.trait_self_param();
     generic_params
         .where_predicates()
+        .iter()
         .filter_map(|pred| match pred {
             WherePredicate::ForLifetime { target, bound, .. }
             | WherePredicate::TypeBound { target, bound } => {
@@ -218,7 +219,7 @@ pub(super) fn associated_type_by_name_including_super_traits(
     name: &Name,
 ) -> Option<(TraitRef, TypeAliasId)> {
     all_super_trait_refs(db, trait_ref, |t| {
-        let assoc_type = db.trait_items(t.hir_trait_id()).associated_type_by_name(name)?;
+        let assoc_type = t.hir_trait_id().trait_items(db).associated_type_by_name(name)?;
         Some((t, assoc_type))
     })
 }
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 08a215fecf6..87d9df611bd 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
@@ -54,14 +54,14 @@ pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> Option<Ar
     variances.is_empty().not().then(|| Arc::from_iter(variances))
 }
 
-// pub(crate) fn variances_of_cycle_fn(
-//     _db: &dyn HirDatabase,
-//     _result: &Option<Arc<[Variance]>>,
-//     _count: u32,
-//     _def: GenericDefId,
-// ) -> salsa::CycleRecoveryAction<Option<Arc<[Variance]>>> {
-//     salsa::CycleRecoveryAction::Iterate
-// }
+pub(crate) fn variances_of_cycle_fn(
+    _db: &dyn HirDatabase,
+    _result: &Option<Arc<[Variance]>>,
+    _count: u32,
+    _def: GenericDefId,
+) -> salsa::CycleRecoveryAction<Option<Arc<[Variance]>>> {
+    salsa::CycleRecoveryAction::Iterate
+}
 
 pub(crate) fn variances_of_cycle_initial(
     db: &dyn HirDatabase,
@@ -965,7 +965,7 @@ struct S3<T>(S<T, T>);
 struct FixedPoint<T, U, V>(&'static FixedPoint<(), T, U>, V);
 "#,
             expect![[r#"
-                FixedPoint[T: bivariant, U: bivariant, V: bivariant]
+                FixedPoint[T: covariant, U: covariant, V: covariant]
             "#]],
         );
     }
diff --git a/src/tools/rust-analyzer/crates/hir/Cargo.toml b/src/tools/rust-analyzer/crates/hir/Cargo.toml
index 2af3c2e4c35..c68ff706e48 100644
--- a/src/tools/rust-analyzer/crates/hir/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 rustc-hash.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 0bce69a179b..c8645b62823 100644
--- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
@@ -207,7 +207,7 @@ fn resolve_assoc_or_field(
             // Doc paths in this context may only resolve to an item of this trait
             // (i.e. no items of its supertraits), so we need to handle them here
             // independently of others.
-            return db.trait_items(id).items.iter().find(|it| it.0 == name).map(|(_, assoc_id)| {
+            return id.trait_items(db).items.iter().find(|it| it.0 == name).map(|(_, assoc_id)| {
                 let def = match *assoc_id {
                     AssocItemId::FunctionId(it) => ModuleDef::Function(it.into()),
                     AssocItemId::ConstId(it) => ModuleDef::Const(it.into()),
diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
index 074bde91fb6..c1e814ec223 100644
--- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
@@ -36,16 +36,16 @@ pub use hir_ty::{
 };
 
 macro_rules! diagnostics {
-    ($($diag:ident $(<$lt:lifetime>)?,)*) => {
+    ($AnyDiagnostic:ident <$db:lifetime> -> $($diag:ident $(<$lt:lifetime>)?,)*) => {
         #[derive(Debug)]
-        pub enum AnyDiagnostic<'db> {$(
+        pub enum $AnyDiagnostic<$db> {$(
             $diag(Box<$diag $(<$lt>)?>),
         )*}
 
         $(
-            impl<'db> From<$diag $(<$lt>)?> for AnyDiagnostic<'db> {
-                fn from(d: $diag $(<$lt>)?) -> AnyDiagnostic<'db> {
-                    AnyDiagnostic::$diag(Box::new(d))
+            impl<$db> From<$diag $(<$lt>)?> for $AnyDiagnostic<$db> {
+                fn from(d: $diag $(<$lt>)?) -> $AnyDiagnostic<$db> {
+                    $AnyDiagnostic::$diag(Box::new(d))
                 }
             }
         )*
@@ -66,7 +66,7 @@ macro_rules! diagnostics {
 // }, ...
 // ]
 
-diagnostics![
+diagnostics![AnyDiagnostic<'db> ->
     AwaitOutsideOfAsync,
     BreakOutsideOfLoop,
     CastToUnsized<'db>,
@@ -490,7 +490,7 @@ impl<'db> AnyDiagnostic<'db> {
     ) -> Option<AnyDiagnostic<'db>> {
         match diagnostic {
             BodyValidationDiagnostic::RecordMissingFields { record, variant, missed_fields } => {
-                let variant_data = variant.variant_data(db);
+                let variant_data = variant.fields(db);
                 let missed_fields = missed_fields
                     .into_iter()
                     .map(|idx| variant_data.fields()[idx].name.clone())
diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs
index 112558bdd04..2960ebedf38 100644
--- a/src/tools/rust-analyzer/crates/hir/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/display.rs
@@ -404,7 +404,7 @@ impl HirDisplay for TupleField {
 impl HirDisplay for Variant {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?;
-        let data = f.db.variant_fields(self.id.into());
+        let data = self.id.fields(f.db);
         match data.shape {
             FieldsShape::Unit => {}
             FieldsShape::Tuple => {
@@ -633,7 +633,7 @@ fn has_disaplayable_predicates(
     params: &GenericParams,
     store: &ExpressionStore,
 ) -> bool {
-    params.where_predicates().any(|pred| {
+    params.where_predicates().iter().any(|pred| {
         !matches!(
             pred,
             WherePredicate::TypeBound { target, .. }
@@ -668,7 +668,7 @@ fn write_where_predicates(
         _ => false,
     };
 
-    let mut iter = params.where_predicates().peekable();
+    let mut iter = params.where_predicates().iter().peekable();
     while let Some(pred) = iter.next() {
         if matches!(pred, TypeBound { target, .. } if is_unnamed_type_target(*target)) {
             continue;
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 3b39707cf60..5c6f622e6c3 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -54,7 +54,7 @@ use hir_def::{
     },
     item_tree::ImportAlias,
     layout::{self, ReprOptions, TargetDataLayout},
-    nameres::{self, diagnostics::DefDiagnostic},
+    nameres::{self, assoc::TraitItems, diagnostics::DefDiagnostic},
     per_ns::PerNs,
     resolver::{HasResolver, Resolver},
     signatures::{ImplFlags, StaticFlags, TraitFlags, VariantFields},
@@ -649,7 +649,7 @@ impl Module {
                     acc.extend(def.diagnostics(db, style_lints))
                 }
                 ModuleDef::Trait(t) => {
-                    for diag in db.trait_items_with_diagnostics(t.id).1.iter() {
+                    for diag in TraitItems::query_with_diagnostics(db, t.id).1.iter() {
                         emit_def_diagnostic(db, acc, diag, edition);
                     }
 
@@ -668,25 +668,25 @@ impl Module {
                         Adt::Struct(s) => {
                             let source_map = db.struct_signature_with_source_map(s.id).1;
                             expr_store_diagnostics(db, acc, &source_map);
-                            let source_map = db.variant_fields_with_source_map(s.id.into()).1;
-                            expr_store_diagnostics(db, acc, &source_map);
+                            let source_map = &s.id.fields_with_source_map(db).1;
+                            expr_store_diagnostics(db, acc, source_map);
                             push_ty_diagnostics(
                                 db,
                                 acc,
                                 db.field_types_with_diagnostics(s.id.into()).1,
-                                &source_map,
+                                source_map,
                             );
                         }
                         Adt::Union(u) => {
                             let source_map = db.union_signature_with_source_map(u.id).1;
                             expr_store_diagnostics(db, acc, &source_map);
-                            let source_map = db.variant_fields_with_source_map(u.id.into()).1;
-                            expr_store_diagnostics(db, acc, &source_map);
+                            let source_map = &u.id.fields_with_source_map(db).1;
+                            expr_store_diagnostics(db, acc, source_map);
                             push_ty_diagnostics(
                                 db,
                                 acc,
                                 db.field_types_with_diagnostics(u.id.into()).1,
-                                &source_map,
+                                source_map,
                             );
                         }
                         Adt::Enum(e) => {
@@ -711,14 +711,14 @@ impl Module {
                                 }
                             }
                             for &(v, _, _) in &variants.variants {
-                                let source_map = db.variant_fields_with_source_map(v.into()).1;
+                                let source_map = &v.fields_with_source_map(db).1;
                                 push_ty_diagnostics(
                                     db,
                                     acc,
                                     db.field_types_with_diagnostics(v.into()).1,
-                                    &source_map,
+                                    source_map,
                                 );
-                                expr_store_diagnostics(db, acc, &source_map);
+                                expr_store_diagnostics(db, acc, source_map);
                             }
                         }
                     }
@@ -822,7 +822,7 @@ impl Module {
 
             // Negative impls can't have items, don't emit missing items diagnostic for them
             if let (false, Some(trait_)) = (impl_is_negative, trait_) {
-                let items = &db.trait_items(trait_.into()).items;
+                let items = &trait_.id.trait_items(db).items;
                 let required_items = items.iter().filter(|&(_, assoc)| match *assoc {
                     AssocItemId::FunctionId(it) => !db.function_signature(it).has_body(),
                     AssocItemId::ConstId(id) => !db.const_signature(id).has_body(),
@@ -1260,7 +1260,9 @@ impl TupleField {
     }
 
     pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> {
-        let ty = db.infer(self.owner).tuple_field_access_types[&self.tuple]
+        let ty = db
+            .infer(self.owner)
+            .tuple_field_access_type(self.tuple)
             .as_slice(Interner)
             .get(self.index as usize)
             .and_then(|arg| arg.ty(Interner))
@@ -1311,7 +1313,7 @@ impl AstNode for FieldSource {
 
 impl Field {
     pub fn name(&self, db: &dyn HirDatabase) -> Name {
-        db.variant_fields(self.parent.into()).fields()[self.id].name.clone()
+        VariantId::from(self.parent).fields(db).fields()[self.id].name.clone()
     }
 
     pub fn index(&self) -> usize {
@@ -1380,7 +1382,7 @@ impl Field {
 
 impl HasVisibility for Field {
     fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
-        let variant_data = db.variant_fields(self.parent.into());
+        let variant_data = VariantId::from(self.parent).fields(db);
         let visibility = &variant_data.fields()[self.id].visibility;
         let parent_id: hir_def::VariantId = self.parent.into();
         // FIXME: RawVisibility::Public doesn't need to construct a resolver
@@ -1403,7 +1405,8 @@ impl Struct {
     }
 
     pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
-        db.variant_fields(self.id.into())
+        self.id
+            .fields(db)
             .fields()
             .iter()
             .map(|(id, _)| Field { parent: self.into(), id })
@@ -1434,8 +1437,8 @@ impl Struct {
         }
     }
 
-    fn variant_fields(self, db: &dyn HirDatabase) -> Arc<VariantFields> {
-        db.variant_fields(self.id.into())
+    fn variant_fields(self, db: &dyn HirDatabase) -> &VariantFields {
+        self.id.fields(db)
     }
 
     pub fn is_unstable(self, db: &dyn HirDatabase) -> bool {
@@ -1478,7 +1481,7 @@ impl Union {
     }
 
     pub fn kind(self, db: &dyn HirDatabase) -> StructKind {
-        match db.variant_fields(self.id.into()).shape {
+        match self.id.fields(db).shape {
             hir_def::item_tree::FieldsShape::Record => StructKind::Record,
             hir_def::item_tree::FieldsShape::Tuple => StructKind::Tuple,
             hir_def::item_tree::FieldsShape::Unit => StructKind::Unit,
@@ -1486,7 +1489,8 @@ impl Union {
     }
 
     pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
-        db.variant_fields(self.id.into())
+        self.id
+            .fields(db)
             .fields()
             .iter()
             .map(|(id, _)| Field { parent: self.into(), id })
@@ -1626,7 +1630,8 @@ impl Variant {
     }
 
     pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
-        db.variant_fields(self.id.into())
+        self.id
+            .fields(db)
             .fields()
             .iter()
             .map(|(id, _)| Field { parent: self.into(), id })
@@ -1634,7 +1639,7 @@ impl Variant {
     }
 
     pub fn kind(self, db: &dyn HirDatabase) -> StructKind {
-        match db.variant_fields(self.id.into()).shape {
+        match self.id.fields(db).shape {
             hir_def::item_tree::FieldsShape::Record => StructKind::Record,
             hir_def::item_tree::FieldsShape::Tuple => StructKind::Tuple,
             hir_def::item_tree::FieldsShape::Unit => StructKind::Unit,
@@ -1727,10 +1732,10 @@ impl Adt {
     pub fn ty_with_args<'db>(
         self,
         db: &'db dyn HirDatabase,
-        args: impl Iterator<Item = Type<'db>>,
+        args: impl IntoIterator<Item = Type<'db>>,
     ) -> Type<'db> {
         let id = AdtId::from(self);
-        let mut it = args.map(|t| t.ty);
+        let mut it = args.into_iter().map(|t| t.ty);
         let ty = TyBuilder::def_ty(db, id.into(), None)
             .fill(|x| {
                 let r = it.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
@@ -1924,7 +1929,7 @@ impl DefWithBody {
         expr_store_diagnostics(db, acc, &source_map);
 
         let infer = db.infer(self.into());
-        for d in &infer.diagnostics {
+        for d in infer.diagnostics() {
             acc.extend(AnyDiagnostic::inference_diagnostic(
                 db,
                 self.into(),
@@ -2883,7 +2888,7 @@ impl Trait {
     }
 
     pub fn function(self, db: &dyn HirDatabase, name: impl PartialEq<Name>) -> Option<Function> {
-        db.trait_items(self.id).items.iter().find(|(n, _)| name == *n).and_then(|&(_, it)| match it
+        self.id.trait_items(db).items.iter().find(|(n, _)| name == *n).and_then(|&(_, it)| match it
         {
             AssocItemId::FunctionId(id) => Some(Function { id }),
             _ => None,
@@ -2891,7 +2896,7 @@ impl Trait {
     }
 
     pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
-        db.trait_items(self.id).items.iter().map(|(_name, it)| (*it).into()).collect()
+        self.id.trait_items(db).items.iter().map(|(_name, it)| (*it).into()).collect()
     }
 
     pub fn items_with_supertraits(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
@@ -2939,7 +2944,7 @@ impl Trait {
     }
 
     fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> {
-        db.trait_items(self.id).macro_calls.to_vec().into_boxed_slice()
+        self.id.trait_items(db).macro_calls.to_vec().into_boxed_slice()
     }
 
     /// `#[rust_analyzer::completions(...)]` mode.
@@ -3043,10 +3048,17 @@ pub struct BuiltinType {
 }
 
 impl BuiltinType {
+    // Constructors are added on demand, feel free to add more.
     pub fn str() -> BuiltinType {
         BuiltinType { inner: hir_def::builtin_type::BuiltinType::Str }
     }
 
+    pub fn i32() -> BuiltinType {
+        BuiltinType {
+            inner: hir_def::builtin_type::BuiltinType::Int(hir_ty::primitive::BuiltinInt::I32),
+        }
+    }
+
     pub fn ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> {
         let core = Crate::core(db).map(|core| core.id).unwrap_or_else(|| db.all_crates()[0]);
         Type::new_for_crate(core, TyBuilder::builtin(self.inner))
@@ -3667,7 +3679,7 @@ impl GenericDef {
 
         let generics = db.generic_params(def);
 
-        if generics.is_empty() && generics.no_predicates() {
+        if generics.is_empty() && generics.has_no_predicates() {
             return;
         }
 
@@ -5000,7 +5012,7 @@ impl<'db> Type<'db> {
         }
 
         let output_assoc_type =
-            db.trait_items(trait_).associated_type_by_name(&Name::new_symbol_root(sym::Output))?;
+            trait_.trait_items(db).associated_type_by_name(&Name::new_symbol_root(sym::Output))?;
         self.normalize_trait_assoc_type(db, &[], output_assoc_type.into())
     }
 
@@ -5013,8 +5025,8 @@ impl<'db> Type<'db> {
     /// This does **not** resolve `IntoIterator`, only `Iterator`.
     pub fn iterator_item(self, db: &'db dyn HirDatabase) -> Option<Type<'db>> {
         let iterator_trait = LangItem::Iterator.resolve_trait(db, self.env.krate)?;
-        let iterator_item = db
-            .trait_items(iterator_trait)
+        let iterator_item = iterator_trait
+            .trait_items(db)
             .associated_type_by_name(&Name::new_symbol_root(sym::Item))?;
         self.normalize_trait_assoc_type(db, &[], iterator_item.into())
     }
@@ -5044,8 +5056,8 @@ impl<'db> Type<'db> {
             return None;
         }
 
-        let into_iter_assoc_type = db
-            .trait_items(trait_)
+        let into_iter_assoc_type = trait_
+            .trait_items(db)
             .associated_type_by_name(&Name::new_symbol_root(sym::IntoIter))?;
         self.normalize_trait_assoc_type(db, &[], into_iter_assoc_type.into())
     }
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index d96975831e0..247bb693983 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -2199,6 +2199,10 @@ pub struct SemanticsScope<'db> {
 }
 
 impl<'db> SemanticsScope<'db> {
+    pub fn file_id(&self) -> HirFileId {
+        self.file_id
+    }
+
     pub fn module(&self) -> Module {
         Module { id: self.resolver.module() }
     }
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 fedd8239d03..e7db93d375d 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
@@ -35,7 +35,7 @@ pub(crate) trait ChildBySource {
 
 impl ChildBySource for TraitId {
     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
-        let data = db.trait_items(*self);
+        let data = self.trait_items(db);
 
         data.macro_calls().filter(|(ast_id, _)| ast_id.file_id == file_id).for_each(
             |(ast_id, call_id)| {
@@ -191,7 +191,7 @@ impl ChildBySource for VariantId {
                 Either::Right(source) => res[keys::RECORD_FIELD].insert(AstPtr::new(&source), id),
             }
         }
-        let (_, sm) = db.variant_fields_with_source_map(*self);
+        let (_, sm) = self.fields_with_source_map(db);
         sm.expansions().for_each(|(ast, &exp_id)| res[keys::MACRO_CALL].insert(ast.value, exp_id));
     }
 }
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 48543ca581f..0662bfddcf8 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -156,14 +156,14 @@ impl<'db> SourceAnalyzer<'db> {
         InFile { file_id, .. }: InFile<&SyntaxNode>,
         _offset: Option<TextSize>,
     ) -> SourceAnalyzer<'db> {
-        let (fields, source_map) = db.variant_fields_with_source_map(def);
+        let (fields, source_map) = def.fields_with_source_map(db);
         let resolver = def.resolver(db);
         SourceAnalyzer {
             resolver,
             body_or_sig: Some(BodyOrSig::VariantFields {
                 def,
                 store: fields.store.clone(),
-                source_map,
+                source_map: source_map.clone(),
             }),
             file_id,
         }
@@ -254,7 +254,7 @@ impl<'db> SourceAnalyzer<'db> {
         // expressions nor patterns).
         let expr_id = self.expr_id(expr.clone())?.as_expr()?;
         let infer = self.infer()?;
-        infer.expr_adjustments.get(&expr_id).map(|v| &**v)
+        infer.expr_adjustment(expr_id)
     }
 
     pub(crate) fn type_of_type(
@@ -286,7 +286,7 @@ impl<'db> SourceAnalyzer<'db> {
         let infer = self.infer()?;
         let coerced = expr_id
             .as_expr()
-            .and_then(|expr_id| infer.expr_adjustments.get(&expr_id))
+            .and_then(|expr_id| infer.expr_adjustment(expr_id))
             .and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.clone()));
         let ty = infer[expr_id].clone();
         let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
@@ -302,12 +302,11 @@ impl<'db> SourceAnalyzer<'db> {
         let infer = self.infer()?;
         let coerced = match expr_or_pat_id {
             ExprOrPatId::ExprId(idx) => infer
-                .expr_adjustments
-                .get(&idx)
+                .expr_adjustment(idx)
                 .and_then(|adjusts| adjusts.last().cloned())
                 .map(|adjust| adjust.target),
             ExprOrPatId::PatId(idx) => {
-                infer.pat_adjustments.get(&idx).and_then(|adjusts| adjusts.last().cloned())
+                infer.pat_adjustment(idx).and_then(|adjusts| adjusts.last().cloned())
             }
         };
 
@@ -345,7 +344,7 @@ impl<'db> SourceAnalyzer<'db> {
     ) -> Option<BindingMode> {
         let id = self.pat_id(&pat.clone().into())?;
         let infer = self.infer()?;
-        infer.binding_modes.get(id.as_pat()?).map(|bm| match bm {
+        infer.binding_mode(id.as_pat()?).map(|bm| match bm {
             hir_ty::BindingMode::Move => BindingMode::Move,
             hir_ty::BindingMode::Ref(hir_ty::Mutability::Mut) => BindingMode::Ref(Mutability::Mut),
             hir_ty::BindingMode::Ref(hir_ty::Mutability::Not) => {
@@ -362,8 +361,7 @@ impl<'db> SourceAnalyzer<'db> {
         let infer = self.infer()?;
         Some(
             infer
-                .pat_adjustments
-                .get(&pat_id.as_pat()?)?
+                .pat_adjustment(pat_id.as_pat()?)?
                 .iter()
                 .map(|ty| Type::new_with_resolver(db, &self.resolver, ty.clone()))
                 .collect(),
@@ -713,7 +711,7 @@ impl<'db> SourceAnalyzer<'db> {
         };
         let (adt, subst) = self.infer()?.type_of_expr_or_pat(expr_id)?.as_adt()?;
         let variant = self.infer()?.variant_resolution_for_expr_or_pat(expr_id)?;
-        let variant_data = variant.variant_data(db);
+        let variant_data = variant.fields(db);
         let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? };
         let field_ty =
             db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, subst);
@@ -734,9 +732,9 @@ impl<'db> SourceAnalyzer<'db> {
         let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
         let pat_id = self.pat_id(&record_pat.into())?;
         let variant = self.infer()?.variant_resolution_for_pat(pat_id.as_pat()?)?;
-        let variant_data = variant.variant_data(db);
+        let variant_data = variant.fields(db);
         let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? };
-        let (adt, subst) = self.infer()?.type_of_pat.get(pat_id.as_pat()?)?.as_adt()?;
+        let (adt, subst) = self.infer()?[pat_id.as_pat()?].as_adt()?;
         let field_ty =
             db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, subst);
         Some((
@@ -765,7 +763,8 @@ impl<'db> SourceAnalyzer<'db> {
             },
         };
 
-        let res = resolve_hir_path(db, &self.resolver, path, HygieneId::ROOT, Some(store))?;
+        let body_owner = self.resolver.body_owner();
+        let res = resolve_hir_value_path(db, &self.resolver, body_owner, path, HygieneId::ROOT)?;
         match res {
             PathResolution::Def(def) => Some(def),
             _ => None,
@@ -803,8 +802,8 @@ impl<'db> SourceAnalyzer<'db> {
                 };
                 container = Either::Right(db.normalize_projection(projection, trait_env.clone()));
             }
-            let handle_variants = |variant, subst: &Substitution, container: &mut _| {
-                let fields = db.variant_fields(variant);
+            let handle_variants = |variant: VariantId, subst: &Substitution, container: &mut _| {
+                let fields = variant.fields(db);
                 let field = fields.field(&field_name.as_name())?;
                 let field_types = db.field_types(variant);
                 *container = Either::Right(field_types[field].clone().substitute(Interner, subst));
@@ -1249,7 +1248,7 @@ impl<'db> SourceAnalyzer<'db> {
         let infer = self.infer()?;
 
         let pat_id = self.pat_id(&pattern.clone().into())?.as_pat()?;
-        let substs = infer.type_of_pat[pat_id].as_adt()?.1;
+        let substs = infer[pat_id].as_adt()?.1;
 
         let (variant, missing_fields, _exhaustive) =
             record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?;
@@ -1423,7 +1422,7 @@ impl<'db> SourceAnalyzer<'db> {
         method_name: &Name,
     ) -> Option<(TraitId, FunctionId)> {
         let trait_id = lang_trait.resolve_trait(db, self.resolver.krate())?;
-        let fn_id = db.trait_items(trait_id).method_by_name(method_name)?;
+        let fn_id = trait_id.trait_items(db).method_by_name(method_name)?;
         Some((trait_id, fn_id))
     }
 
@@ -1580,7 +1579,7 @@ fn resolve_hir_path_(
         // within the trait's associated types.
         if let (Some(unresolved), &TypeNs::TraitId(trait_id)) = (&unresolved, &ty) {
             if let Some(type_alias_id) =
-                db.trait_items(trait_id).associated_type_by_name(unresolved.name)
+                trait_id.trait_items(db).associated_type_by_name(unresolved.name)
             {
                 return Some(PathResolution::Def(ModuleDefId::from(type_alias_id).into()));
             }
@@ -1731,7 +1730,7 @@ fn resolve_hir_path_qualifier(
         // within the trait's associated types.
         if let (Some(unresolved), &TypeNs::TraitId(trait_id)) = (&unresolved, &ty) {
             if let Some(type_alias_id) =
-                db.trait_items(trait_id).associated_type_by_name(unresolved.name)
+                trait_id.trait_items(db).associated_type_by_name(unresolved.name)
             {
                 return Some(PathResolution::Def(ModuleDefId::from(type_alias_id).into()));
             }
@@ -1785,8 +1784,8 @@ pub(crate) fn name_hygiene(db: &dyn HirDatabase, name: InFile<&SyntaxNode>) -> H
 }
 
 fn type_of_expr_including_adjust(infer: &InferenceResult, id: ExprId) -> Option<&Ty> {
-    match infer.expr_adjustments.get(&id).and_then(|adjustments| adjustments.last()) {
+    match infer.expr_adjustment(id).and_then(|adjustments| adjustments.last()) {
         Some(adjustment) => Some(&adjustment.target),
-        None => infer.type_of_expr.get(id),
+        None => Some(&infer[id]),
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
index 64f2a910bd1..756650891d4 100644
--- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
@@ -334,7 +334,7 @@ impl<'a> SymbolCollector<'a> {
     fn collect_from_trait(&mut self, trait_id: TraitId, trait_do_not_complete: Complete) {
         let trait_data = self.db.trait_signature(trait_id);
         self.with_container_name(Some(trait_data.name.as_str().into()), |s| {
-            for &(ref name, assoc_item_id) in &self.db.trait_items(trait_id).items {
+            for &(ref name, assoc_item_id) in &trait_id.trait_items(self.db).items {
                 s.push_assoc_item(assoc_item_id, name, Some(trait_do_not_complete));
             }
         });
diff --git a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml
index 53af980c194..385b0e1eb7c 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 cov-mark = "2.0.0"
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs
index b71de5e00c6..c80b78fd970 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs
@@ -175,7 +175,7 @@ pub(crate) fn expand_rest_pattern(acc: &mut Assists, ctx: &AssistContext<'_>) ->
             // ast::TuplePat(it) => (),
             // FIXME
             // ast::SlicePat(it) => (),
-            _ => return None,
+            _ => None,
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs
index 3e6d0bec68a..517906b429a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs
@@ -1,3 +1,5 @@
+use std::slice;
+
 use ide_db::assists::GroupLabel;
 use stdx::to_lower_snake_case;
 use syntax::ast::HasVisibility;
@@ -52,7 +54,7 @@ pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext<'_>
     let fn_name = format!("is_{}", &to_lower_snake_case(&variant_name.text()));
 
     // Return early if we've found an existing new fn
-    let impl_def = find_struct_impl(ctx, &parent_enum, &[fn_name.clone()])?;
+    let impl_def = find_struct_impl(ctx, &parent_enum, slice::from_ref(&fn_name))?;
 
     let target = variant.syntax().text_range();
     acc.add_group(
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs
index 3974bcf6187..e4b0f830497 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs
@@ -1,3 +1,5 @@
+use std::slice;
+
 use ide_db::assists::GroupLabel;
 use itertools::Itertools;
 use stdx::to_lower_snake_case;
@@ -148,7 +150,7 @@ fn generate_enum_projection_method(
     let fn_name = format!("{fn_name_prefix}_{}", &to_lower_snake_case(&variant_name.text()));
 
     // Return early if we've found an existing new fn
-    let impl_def = find_struct_impl(ctx, &parent_enum, &[fn_name.clone()])?;
+    let impl_def = find_struct_impl(ctx, &parent_enum, slice::from_ref(&fn_name))?;
 
     let target = variant.syntax().text_range();
     acc.add_group(
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs
index 6316a8f0db2..603be4d6673 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs
@@ -3,8 +3,7 @@ use ide_db::{assists::AssistId, defs::Definition};
 use stdx::to_upper_snake_case;
 use syntax::{
     AstNode,
-    ast::{self, HasName, make},
-    ted,
+    ast::{self, HasName, syntax_factory::SyntaxFactory},
 };
 
 use crate::{
@@ -69,15 +68,18 @@ pub(crate) fn promote_local_to_const(acc: &mut Assists, ctx: &AssistContext<'_>)
         "Promote local to constant",
         let_stmt.syntax().text_range(),
         |edit| {
+            let make = SyntaxFactory::with_mappings();
+            let mut editor = edit.make_editor(let_stmt.syntax());
             let name = to_upper_snake_case(&name.to_string());
             let usages = Definition::Local(local).usages(&ctx.sema).all();
             if let Some(usages) = usages.references.get(&ctx.file_id()) {
-                let name_ref = make::name_ref(&name);
+                let name_ref = make.name_ref(&name);
 
                 for usage in usages {
                     let Some(usage_name) = usage.name.as_name_ref().cloned() else { continue };
                     if let Some(record_field) = ast::RecordExprField::for_name_ref(&usage_name) {
-                        let name_expr = make::expr_path(make::path_from_text(&name));
+                        let path = make.ident_path(&name);
+                        let name_expr = make.expr_path(path);
                         utils::replace_record_field_expr(ctx, edit, record_field, name_expr);
                     } else {
                         let usage_range = usage.range;
@@ -86,15 +88,17 @@ pub(crate) fn promote_local_to_const(acc: &mut Assists, ctx: &AssistContext<'_>)
                 }
             }
 
-            let item = make::item_const(None, make::name(&name), make::ty(&ty), initializer)
-                .clone_for_update();
-            let let_stmt = edit.make_mut(let_stmt);
+            let item = make.item_const(None, make.name(&name), make.ty(&ty), initializer);
 
             if let Some((cap, name)) = ctx.config.snippet_cap.zip(item.name()) {
-                edit.add_tabstop_before(cap, name);
+                let tabstop = edit.make_tabstop_before(cap);
+                editor.add_annotation(name.syntax().clone(), tabstop);
             }
 
-            ted::replace(let_stmt.syntax(), item.syntax());
+            editor.replace(let_stmt.syntax(), item.syntax());
+
+            editor.add_mappings(make.finish_with_mappings());
+            edit.add_file_edits(ctx.vfs_file_id(), editor);
         },
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
index e933bcc40db..62914ee7f38 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
@@ -1,8 +1,5 @@
 use ide_db::syntax_helpers::suggest_name;
-use syntax::{
-    ast::{self, AstNode, make},
-    ted,
-};
+use syntax::ast::{self, AstNode, syntax_factory::SyntaxFactory};
 
 use crate::{AssistContext, AssistId, Assists};
 
@@ -60,21 +57,25 @@ pub(crate) fn replace_is_method_with_if_let_method(
                 message,
                 call_expr.syntax().text_range(),
                 |edit| {
-                    let call_expr = edit.make_mut(call_expr);
+                    let make = SyntaxFactory::with_mappings();
+                    let mut editor = edit.make_editor(call_expr.syntax());
 
-                    let var_pat = make::ident_pat(false, false, make::name(&var_name));
-                    let pat = make::tuple_struct_pat(make::ext::ident_path(text), [var_pat.into()]);
-                    let let_expr = make::expr_let(pat.into(), receiver).clone_for_update();
+                    let var_pat = make.ident_pat(false, false, make.name(&var_name));
+                    let pat = make.tuple_struct_pat(make.ident_path(text), [var_pat.into()]);
+                    let let_expr = make.expr_let(pat.into(), receiver);
 
                     if let Some(cap) = ctx.config.snippet_cap {
                         if let Some(ast::Pat::TupleStructPat(pat)) = let_expr.pat() {
                             if let Some(first_var) = pat.fields().next() {
-                                edit.add_placeholder_snippet(cap, first_var);
+                                let placeholder = edit.make_placeholder_snippet(cap);
+                                editor.add_annotation(first_var.syntax(), placeholder);
                             }
                         }
                     }
 
-                    ted::replace(call_expr.syntax(), let_expr.syntax());
+                    editor.replace(call_expr.syntax(), let_expr.syntax());
+                    editor.add_mappings(make.finish_with_mappings());
+                    edit.add_file_edits(ctx.vfs_file_id(), editor);
                 },
             )
         }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
index 019ddaf1441..6527d3706e2 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
@@ -100,9 +100,7 @@ fn f() { let a: u128 = 1; let b: u128 = todo$0!() }"#,
     fn test_complete_todo_with_msg() {
         check_assist(
             term_search,
-            // FIXME: Since we are lacking of `super let`, term search fails due to borrowck failure.
-            // Should implement super let and remove `fmt_before_1_89_0`
-            r#"//- minicore: todo, unimplemented, fmt_before_1_89_0
+            r#"//- minicore: todo, unimplemented
 fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
             r#"fn f() { let a: u128 = 1; let b: u128 = a }"#,
         )
@@ -112,10 +110,8 @@ fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
     fn test_complete_unimplemented_with_msg() {
         check_assist(
             term_search,
-            // FIXME: Since we are lacking of `super let`, term search fails due to borrowck failure.
-            // Should implement super let and remove `fmt_before_1_89_0`
-            r#"//- minicore: todo, unimplemented, fmt_before_1_89_0
-fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
+            r#"//- minicore: todo, unimplemented
+fn f() { let a: u128 = 1; let b: u128 = unimplemented$0!("asd") }"#,
             r#"fn f() { let a: u128 = 1; let b: u128 = a }"#,
         )
     }
@@ -124,10 +120,8 @@ fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
     fn test_complete_unimplemented() {
         check_assist(
             term_search,
-            // FIXME: Since we are lacking of `super let`, term search fails due to borrowck failure.
-            // Should implement super let and remove `fmt_before_1_89_0`
-            r#"//- minicore: todo, unimplemented, fmt_before_1_89_0
-fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
+            r#"//- minicore: todo, unimplemented
+fn f() { let a: u128 = 1; let b: u128 = unimplemented$0!() }"#,
             r#"fn f() { let a: u128 = 1; let b: u128 = a }"#,
         )
     }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs
index 109269bd6e6..504e12f93df 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs
@@ -1,8 +1,7 @@
 use ide_db::assists::AssistId;
 use syntax::{
     AstNode, T,
-    ast::{self, make},
-    ted,
+    ast::{self, syntax_factory::SyntaxFactory},
 };
 
 use crate::{AssistContext, Assists};
@@ -37,8 +36,7 @@ pub(crate) fn toggle_macro_delimiter(acc: &mut Assists, ctx: &AssistContext<'_>)
         RCur,
     }
 
-    let makro = ctx.find_node_at_offset::<ast::MacroCall>()?.clone_for_update();
-    let makro_text_range = makro.syntax().text_range();
+    let makro = ctx.find_node_at_offset::<ast::MacroCall>()?;
 
     let cursor_offset = ctx.offset();
     let semicolon = makro.semicolon_token();
@@ -71,24 +69,28 @@ pub(crate) fn toggle_macro_delimiter(acc: &mut Assists, ctx: &AssistContext<'_>)
         },
         token_tree.syntax().text_range(),
         |builder| {
+            let make = SyntaxFactory::with_mappings();
+            let mut editor = builder.make_editor(makro.syntax());
+
             match token {
                 MacroDelims::LPar | MacroDelims::RPar => {
-                    ted::replace(ltoken, make::token(T!['{']));
-                    ted::replace(rtoken, make::token(T!['}']));
+                    editor.replace(ltoken, make.token(T!['{']));
+                    editor.replace(rtoken, make.token(T!['}']));
                     if let Some(sc) = semicolon {
-                        ted::remove(sc);
+                        editor.delete(sc);
                     }
                 }
                 MacroDelims::LBra | MacroDelims::RBra => {
-                    ted::replace(ltoken, make::token(T!['(']));
-                    ted::replace(rtoken, make::token(T![')']));
+                    editor.replace(ltoken, make.token(T!['(']));
+                    editor.replace(rtoken, make.token(T![')']));
                 }
                 MacroDelims::LCur | MacroDelims::RCur => {
-                    ted::replace(ltoken, make::token(T!['[']));
-                    ted::replace(rtoken, make::token(T![']']));
+                    editor.replace(ltoken, make.token(T!['[']));
+                    editor.replace(rtoken, make.token(T![']']));
                 }
             }
-            builder.replace(makro_text_range, makro.syntax().text());
+            editor.add_mappings(make.finish_with_mappings());
+            builder.add_file_edits(ctx.vfs_file_id(), editor);
         },
     )
 }
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 5aedff5cc77..7b0f2dc65a7 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
@@ -1,8 +1,7 @@
 use syntax::{
     Direction, SyntaxKind, T,
-    algo::neighbor,
-    ast::{self, AstNode, edit::IndentLevel, make},
-    ted::{self, Position},
+    ast::{self, AstNode, edit::IndentLevel, syntax_factory::SyntaxFactory},
+    syntax_editor::{Element, Position},
 };
 
 use crate::{AssistContext, AssistId, Assists};
@@ -33,7 +32,7 @@ use crate::{AssistContext, AssistId, Assists};
 // ```
 pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let pipe_token = ctx.find_token_syntax_at_offset(T![|])?;
-    let or_pat = ast::OrPat::cast(pipe_token.parent()?)?.clone_for_update();
+    let or_pat = ast::OrPat::cast(pipe_token.parent()?)?;
     if or_pat.leading_pipe().is_some_and(|it| it == pipe_token) {
         return None;
     }
@@ -44,13 +43,14 @@ pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
     // without `OrPat`.
 
     let new_parent = match_arm.syntax().parent()?;
-    let old_parent_range = new_parent.text_range();
 
     acc.add(
         AssistId::refactor_rewrite("unmerge_match_arm"),
         "Unmerge match arm",
         pipe_token.text_range(),
         |edit| {
+            let make = SyntaxFactory::with_mappings();
+            let mut editor = edit.make_editor(&new_parent);
             let pats_after = pipe_token
                 .siblings_with_tokens(Direction::Next)
                 .filter_map(|it| ast::Pat::cast(it.into_node()?))
@@ -59,11 +59,9 @@ pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
             let new_pat = if pats_after.len() == 1 {
                 pats_after[0].clone()
             } else {
-                make::or_pat(pats_after, or_pat.leading_pipe().is_some()).into()
+                make.or_pat(pats_after, or_pat.leading_pipe().is_some()).into()
             };
-            let new_match_arm =
-                make::match_arm(new_pat, match_arm.guard(), match_arm_body).clone_for_update();
-
+            let new_match_arm = make.match_arm(new_pat, match_arm.guard(), match_arm_body);
             let mut pipe_index = pipe_token.index();
             if pipe_token
                 .prev_sibling_or_token()
@@ -71,10 +69,13 @@ pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
             {
                 pipe_index -= 1;
             }
-            or_pat.syntax().splice_children(
-                pipe_index..or_pat.syntax().children_with_tokens().count(),
-                Vec::new(),
-            );
+            for child in or_pat
+                .syntax()
+                .children_with_tokens()
+                .skip_while(|child| child.index() < pipe_index)
+            {
+                editor.delete(child.syntax_element());
+            }
 
             let mut insert_after_old_arm = Vec::new();
 
@@ -86,33 +87,19 @@ pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
             //    body is a block, but we don't bother to check that.
             //  - Missing after the arm with arms after, if the arm body is a block. In this case
             //    we don't want to insert a comma at all.
-            let has_comma_after =
-                std::iter::successors(match_arm.syntax().last_child_or_token(), |it| {
-                    it.prev_sibling_or_token()
-                })
-                .map(|it| it.kind())
-                .find(|it| !it.is_trivia())
-                    == Some(T![,]);
-            let has_arms_after = neighbor(&match_arm, Direction::Next).is_some();
-            if !has_comma_after && !has_arms_after {
-                insert_after_old_arm.push(make::token(T![,]).into());
+            let has_comma_after = match_arm.comma_token().is_some();
+            if !has_comma_after && !match_arm.expr().unwrap().is_block_like() {
+                insert_after_old_arm.push(make.token(T![,]).into());
             }
 
             let indent = IndentLevel::from_node(match_arm.syntax());
-            insert_after_old_arm.push(make::tokens::whitespace(&format!("\n{indent}")).into());
+            insert_after_old_arm.push(make.whitespace(&format!("\n{indent}")).into());
 
             insert_after_old_arm.push(new_match_arm.syntax().clone().into());
 
-            ted::insert_all_raw(Position::after(match_arm.syntax()), insert_after_old_arm);
-
-            if has_comma_after {
-                ted::insert_raw(
-                    Position::last_child_of(new_match_arm.syntax()),
-                    make::token(T![,]),
-                );
-            }
-
-            edit.replace(old_parent_range, new_parent.to_string());
+            editor.insert_all(Position::after(match_arm.syntax()), insert_after_old_arm);
+            editor.add_mappings(make.finish_with_mappings());
+            edit.add_file_edits(ctx.vfs_file_id(), editor);
         },
     )
 }
@@ -258,7 +245,7 @@ fn main() {
     let x = X::A;
     let y = match x {
         X::A => 1i32,
-        X::B => 1i32
+        X::B => 1i32,
     };
 }
 "#,
@@ -276,7 +263,7 @@ enum X { A, B }
 fn main() {
     let x = X::A;
     match x {
-        X::A $0| X::B => {},
+        X::A $0| X::B => {}
     }
 }
 "#,
@@ -287,8 +274,8 @@ enum X { A, B }
 fn main() {
     let x = X::A;
     match x {
-        X::A => {},
-        X::B => {},
+        X::A => {}
+        X::B => {}
     }
 }
 "#,
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 9ea78719b20..d7189aa5dbb 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
@@ -56,7 +56,8 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
     };
 
     let type_ref = &ret_type.ty()?;
-    let ty = ctx.sema.resolve_type(type_ref)?.as_adt();
+    let ty = ctx.sema.resolve_type(type_ref)?;
+    let ty_adt = ty.as_adt();
     let famous_defs = FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax())?.krate());
 
     for kind in WrapperKind::ALL {
@@ -64,7 +65,7 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
             continue;
         };
 
-        if matches!(ty, Some(hir::Adt::Enum(ret_type)) if ret_type == core_wrapper) {
+        if matches!(ty_adt, Some(hir::Adt::Enum(ret_type)) if ret_type == core_wrapper) {
             // The return type is already wrapped
             cov_mark::hit!(wrap_return_type_simple_return_type_already_wrapped);
             continue;
@@ -78,10 +79,23 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
             |builder| {
                 let mut editor = builder.make_editor(&parent);
                 let make = SyntaxFactory::with_mappings();
-                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 alias = wrapper_alias(ctx, &make, core_wrapper, type_ref, &ty, kind.symbol());
+                let (ast_new_return_ty, semantic_new_return_ty) = alias.unwrap_or_else(|| {
+                    let (ast_ty, ty_constructor) = match kind {
+                        WrapperKind::Option => {
+                            (make.ty_option(type_ref.clone()), famous_defs.core_option_Option())
+                        }
+                        WrapperKind::Result => (
+                            make.ty_result(type_ref.clone(), make.ty_infer().into()),
+                            famous_defs.core_result_Result(),
+                        ),
+                    };
+                    let semantic_ty = ty_constructor
+                        .map(|ty_constructor| {
+                            hir::Adt::from(ty_constructor).ty_with_args(ctx.db(), [ty.clone()])
+                        })
+                        .unwrap_or_else(|| ty.clone());
+                    (ast_ty, semantic_ty)
                 });
 
                 let mut exprs_to_wrap = Vec::new();
@@ -96,6 +110,17 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
                 for_each_tail_expr(&body_expr, tail_cb);
 
                 for ret_expr_arg in exprs_to_wrap {
+                    if let Some(ty) = ctx.sema.type_of_expr(&ret_expr_arg) {
+                        if ty.adjusted().could_unify_with(ctx.db(), &semantic_new_return_ty) {
+                            // The type is already correct, don't wrap it.
+                            // We deliberately don't use `could_unify_with_deeply()`, because as long as the outer
+                            // enum matches it's okay for us, as we don't trigger the assist if the return type
+                            // is already `Option`/`Result`, so mismatched exact type is more likely a mistake
+                            // than something intended.
+                            continue;
+                        }
+                    }
+
                     let happy_wrapped = make.expr_call(
                         make.expr_path(make.ident_path(kind.happy_ident())),
                         make.arg_list(iter::once(ret_expr_arg.clone())),
@@ -103,12 +128,12 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
                     editor.replace(ret_expr_arg.syntax(), happy_wrapped.syntax());
                 }
 
-                editor.replace(type_ref.syntax(), new_return_ty.syntax());
+                editor.replace(type_ref.syntax(), ast_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
+                    let args = ast_new_return_ty
                         .path()
                         .unwrap()
                         .segment()
@@ -188,27 +213,28 @@ impl WrapperKind {
 }
 
 // Try to find an wrapper type alias in the current scope (shadowing the default).
-fn wrapper_alias(
-    ctx: &AssistContext<'_>,
+fn wrapper_alias<'db>(
+    ctx: &AssistContext<'db>,
     make: &SyntaxFactory,
-    core_wrapper: &hir::Enum,
-    ret_type: &ast::Type,
+    core_wrapper: hir::Enum,
+    ast_ret_type: &ast::Type,
+    semantic_ret_type: &hir::Type<'db>,
     wrapper: hir::Symbol,
-) -> Option<ast::PathType> {
+) -> Option<(ast::PathType, hir::Type<'db>)> {
     let wrapper_path = hir::ModPath::from_segments(
         hir::PathKind::Plain,
         iter::once(hir::Name::new_symbol_root(wrapper)),
     );
 
-    ctx.sema.resolve_mod_path(ret_type.syntax(), &wrapper_path).and_then(|def| {
+    ctx.sema.resolve_mod_path(ast_ret_type.syntax(), &wrapper_path).and_then(|def| {
         def.filter_map(|def| match def.into_module_def() {
             hir::ModuleDef::TypeAlias(alias) => {
                 let enum_ty = alias.ty(ctx.db()).as_adt()?.as_enum()?;
-                (&enum_ty == core_wrapper).then_some(alias)
+                (enum_ty == core_wrapper).then_some((alias, enum_ty))
             }
             _ => None,
         })
-        .find_map(|alias| {
+        .find_map(|(alias, enum_ty)| {
             let mut inserted_ret_type = false;
             let generic_args =
                 alias.source(ctx.db())?.value.generic_param_list()?.generic_params().map(|param| {
@@ -216,7 +242,7 @@ fn wrapper_alias(
                         // 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()
+                            make.type_arg(ast_ret_type.clone()).into()
                         }
                         ast::GenericParam::LifetimeParam(_) => {
                             make.lifetime_arg(make.lifetime("'_")).into()
@@ -231,7 +257,10 @@ fn wrapper_alias(
                 make.path_segment_generics(make.name_ref(name.as_str()), generic_arg_list),
             );
 
-            Some(make.ty_path(path))
+            let new_ty =
+                hir::Adt::from(enum_ty).ty_with_args(ctx.db(), [semantic_ret_type.clone()]);
+
+            Some((make.ty_path(path), new_ty))
         })
     })
 }
@@ -605,29 +634,39 @@ fn foo() -> Option<i32> {
         check_assist_by_label(
             wrap_return_type,
             r#"
-//- minicore: option
+//- minicore: option, future
+struct F(i32);
+impl core::future::Future for F {
+    type Output = i32;
+    fn poll(self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> core::task::Poll<Self::Output> { 0 }
+}
 async fn foo() -> i$032 {
     if true {
         if false {
-            1.await
+            F(1).await
         } else {
-            2.await
+            F(2).await
         }
     } else {
-        24i32.await
+        F(24i32).await
     }
 }
 "#,
             r#"
+struct F(i32);
+impl core::future::Future for F {
+    type Output = i32;
+    fn poll(self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> core::task::Poll<Self::Output> { 0 }
+}
 async fn foo() -> Option<i32> {
     if true {
         if false {
-            Some(1.await)
+            Some(F(1).await)
         } else {
-            Some(2.await)
+            Some(F(2).await)
         }
     } else {
-        Some(24i32.await)
+        Some(F(24i32).await)
     }
 }
 "#,
@@ -1666,29 +1705,39 @@ fn foo() -> Result<i32, ${0:_}> {
         check_assist_by_label(
             wrap_return_type,
             r#"
-//- minicore: result
+//- minicore: result, future
+struct F(i32);
+impl core::future::Future for F {
+    type Output = i32;
+    fn poll(self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> core::task::Poll<Self::Output> { 0 }
+}
 async fn foo() -> i$032 {
     if true {
         if false {
-            1.await
+            F(1).await
         } else {
-            2.await
+            F(2).await
         }
     } else {
-        24i32.await
+        F(24i32).await
     }
 }
 "#,
             r#"
+struct F(i32);
+impl core::future::Future for F {
+    type Output = i32;
+    fn poll(self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> core::task::Poll<Self::Output> { 0 }
+}
 async fn foo() -> Result<i32, ${0:_}> {
     if true {
         if false {
-            Ok(1.await)
+            Ok(F(1).await)
         } else {
-            Ok(2.await)
+            Ok(F(2).await)
         }
     } else {
-        Ok(24i32.await)
+        Ok(F(24i32).await)
     }
 }
 "#,
@@ -2460,4 +2509,54 @@ fn foo() -> Result<i32, ${0:_}> {
             WrapperKind::Result.label(),
         );
     }
+
+    #[test]
+    fn already_wrapped() {
+        check_assist_by_label(
+            wrap_return_type,
+            r#"
+//- minicore: option
+fn foo() -> i32$0 {
+    if false {
+        0
+    } else {
+        Some(1)
+    }
+}
+            "#,
+            r#"
+fn foo() -> Option<i32> {
+    if false {
+        Some(0)
+    } else {
+        Some(1)
+    }
+}
+            "#,
+            WrapperKind::Option.label(),
+        );
+        check_assist_by_label(
+            wrap_return_type,
+            r#"
+//- minicore: result
+fn foo() -> i32$0 {
+    if false {
+        0
+    } else {
+        Ok(1)
+    }
+}
+            "#,
+            r#"
+fn foo() -> Result<i32, ${0:_}> {
+    if false {
+        Ok(0)
+    } else {
+        Ok(1)
+    }
+}
+            "#,
+            WrapperKind::Result.label(),
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs
index e1b94673e77..5183566d136 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs
@@ -2,8 +2,7 @@ use ide_db::source_change::SourceChangeBuilder;
 use itertools::Itertools;
 use syntax::{
     NodeOrToken, SyntaxToken, T, TextRange, algo,
-    ast::{self, AstNode, make},
-    ted::{self, Position},
+    ast::{self, AstNode, make, syntax_factory::SyntaxFactory},
 };
 
 use crate::{AssistContext, AssistId, Assists};
@@ -173,40 +172,45 @@ fn wrap_derive(
         }
     }
     let handle_source_change = |edit: &mut SourceChangeBuilder| {
-        let new_derive = make::attr_outer(make::meta_token_tree(
-            make::ext::ident_path("derive"),
-            make::token_tree(T!['('], new_derive),
-        ))
-        .clone_for_update();
-        let meta = make::meta_token_tree(
-            make::ext::ident_path("cfg_attr"),
-            make::token_tree(
+        let make = SyntaxFactory::with_mappings();
+        let mut editor = edit.make_editor(attr.syntax());
+        let new_derive = make.attr_outer(
+            make.meta_token_tree(make.ident_path("derive"), make.token_tree(T!['('], new_derive)),
+        );
+        let meta = make.meta_token_tree(
+            make.ident_path("cfg_attr"),
+            make.token_tree(
                 T!['('],
                 vec![
-                    NodeOrToken::Token(make::token(T![,])),
-                    NodeOrToken::Token(make::tokens::whitespace(" ")),
-                    NodeOrToken::Token(make::tokens::ident("derive")),
-                    NodeOrToken::Node(make::token_tree(T!['('], cfg_derive_tokens)),
+                    NodeOrToken::Token(make.token(T![,])),
+                    NodeOrToken::Token(make.whitespace(" ")),
+                    NodeOrToken::Token(make.ident("derive")),
+                    NodeOrToken::Node(make.token_tree(T!['('], cfg_derive_tokens)),
                 ],
             ),
         );
-        // Remove the derive attribute
-        let edit_attr = edit.make_syntax_mut(attr.syntax().clone());
-
-        ted::replace(edit_attr, new_derive.syntax().clone());
-        let cfg_attr = make::attr_outer(meta).clone_for_update();
 
-        ted::insert_all_raw(
-            Position::after(new_derive.syntax().clone()),
-            vec![make::tokens::whitespace("\n").into(), cfg_attr.syntax().clone().into()],
+        let cfg_attr = make.attr_outer(meta);
+        editor.replace_with_many(
+            attr.syntax(),
+            vec![
+                new_derive.syntax().clone().into(),
+                make.whitespace("\n").into(),
+                cfg_attr.syntax().clone().into(),
+            ],
         );
+
         if let Some(snippet_cap) = ctx.config.snippet_cap {
             if let Some(first_meta) =
                 cfg_attr.meta().and_then(|meta| meta.token_tree()).and_then(|tt| tt.l_paren_token())
             {
-                edit.add_tabstop_after_token(snippet_cap, first_meta)
+                let tabstop = edit.make_tabstop_after(snippet_cap);
+                editor.add_annotation(first_meta, tabstop);
             }
         }
+
+        editor.add_mappings(make.finish_with_mappings());
+        edit.add_file_edits(ctx.vfs_file_id(), editor);
     };
 
     acc.add(
@@ -221,10 +225,10 @@ fn wrap_cfg_attr(acc: &mut Assists, ctx: &AssistContext<'_>, attr: ast::Attr) ->
     let range = attr.syntax().text_range();
     let path = attr.path()?;
     let handle_source_change = |edit: &mut SourceChangeBuilder| {
-        let mut raw_tokens = vec![
-            NodeOrToken::Token(make::token(T![,])),
-            NodeOrToken::Token(make::tokens::whitespace(" ")),
-        ];
+        let make = SyntaxFactory::with_mappings();
+        let mut editor = edit.make_editor(attr.syntax());
+        let mut raw_tokens =
+            vec![NodeOrToken::Token(make.token(T![,])), NodeOrToken::Token(make.whitespace(" "))];
         path.syntax().descendants_with_tokens().for_each(|it| {
             if let NodeOrToken::Token(token) = it {
                 raw_tokens.push(NodeOrToken::Token(token));
@@ -232,9 +236,9 @@ fn wrap_cfg_attr(acc: &mut Assists, ctx: &AssistContext<'_>, attr: ast::Attr) ->
         });
         if let Some(meta) = attr.meta() {
             if let (Some(eq), Some(expr)) = (meta.eq_token(), meta.expr()) {
-                raw_tokens.push(NodeOrToken::Token(make::tokens::whitespace(" ")));
+                raw_tokens.push(NodeOrToken::Token(make.whitespace(" ")));
                 raw_tokens.push(NodeOrToken::Token(eq));
-                raw_tokens.push(NodeOrToken::Token(make::tokens::whitespace(" ")));
+                raw_tokens.push(NodeOrToken::Token(make.whitespace(" ")));
 
                 expr.syntax().descendants_with_tokens().for_each(|it| {
                     if let NodeOrToken::Token(token) = it {
@@ -245,26 +249,24 @@ fn wrap_cfg_attr(acc: &mut Assists, ctx: &AssistContext<'_>, attr: ast::Attr) ->
                 raw_tokens.extend(tt.token_trees_and_tokens());
             }
         }
-        let meta = make::meta_token_tree(
-            make::ext::ident_path("cfg_attr"),
-            make::token_tree(T!['('], raw_tokens),
-        );
-        let cfg_attr = if attr.excl_token().is_some() {
-            make::attr_inner(meta)
-        } else {
-            make::attr_outer(meta)
-        }
-        .clone_for_update();
-        let attr_syntax = edit.make_syntax_mut(attr.syntax().clone());
-        ted::replace(attr_syntax, cfg_attr.syntax());
+        let meta =
+            make.meta_token_tree(make.ident_path("cfg_attr"), make.token_tree(T!['('], raw_tokens));
+        let cfg_attr =
+            if attr.excl_token().is_some() { make.attr_inner(meta) } else { make.attr_outer(meta) };
+
+        editor.replace(attr.syntax(), cfg_attr.syntax());
 
         if let Some(snippet_cap) = ctx.config.snippet_cap {
             if let Some(first_meta) =
                 cfg_attr.meta().and_then(|meta| meta.token_tree()).and_then(|tt| tt.l_paren_token())
             {
-                edit.add_tabstop_after_token(snippet_cap, first_meta)
+                let tabstop = edit.make_tabstop_after(snippet_cap);
+                editor.add_annotation(first_meta, tabstop);
             }
         }
+
+        editor.add_mappings(make.finish_with_mappings());
+        edit.add_file_edits(ctx.vfs_file_id(), editor);
     };
     acc.add(
         AssistId::refactor("wrap_unwrap_cfg_attr"),
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 1a91053f93c..87a4c2ef758 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
@@ -1,5 +1,7 @@
 //! Assorted functions shared by several assists.
 
+use std::slice;
+
 pub(crate) use gen_trait_fn_body::gen_trait_fn_body;
 use hir::{
     DisplayTarget, HasAttrs as HirHasAttrs, HirDisplay, InFile, ModuleDef, PathResolution,
@@ -912,7 +914,7 @@ fn handle_as_ref_str(
 ) -> Option<(ReferenceConversionType, bool)> {
     let str_type = hir::BuiltinType::str().ty(db);
 
-    ty.impls_trait(db, famous_defs.core_convert_AsRef()?, &[str_type.clone()])
+    ty.impls_trait(db, famous_defs.core_convert_AsRef()?, slice::from_ref(&str_type))
         .then_some((ReferenceConversionType::AsRefStr, could_deref_to_target(ty, &str_type, db)))
 }
 
@@ -924,7 +926,7 @@ fn handle_as_ref_slice(
     let type_argument = ty.type_arguments().next()?;
     let slice_type = hir::Type::new_slice(type_argument);
 
-    ty.impls_trait(db, famous_defs.core_convert_AsRef()?, &[slice_type.clone()]).then_some((
+    ty.impls_trait(db, famous_defs.core_convert_AsRef()?, slice::from_ref(&slice_type)).then_some((
         ReferenceConversionType::AsRefSlice,
         could_deref_to_target(ty, &slice_type, db),
     ))
@@ -937,10 +939,11 @@ fn handle_dereferenced(
 ) -> Option<(ReferenceConversionType, bool)> {
     let type_argument = ty.type_arguments().next()?;
 
-    ty.impls_trait(db, famous_defs.core_convert_AsRef()?, &[type_argument.clone()]).then_some((
-        ReferenceConversionType::Dereferenced,
-        could_deref_to_target(ty, &type_argument, db),
-    ))
+    ty.impls_trait(db, famous_defs.core_convert_AsRef()?, slice::from_ref(&type_argument))
+        .then_some((
+            ReferenceConversionType::Dereferenced,
+            could_deref_to_target(ty, &type_argument, db),
+        ))
 }
 
 fn handle_option_as_ref(
diff --git a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml
index 94c01e333ed..9bad21fc8e9 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 cov-mark = "2.0.0"
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs
index 6d1e973dc4c..809e71cc119 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs
@@ -195,5 +195,5 @@ fn comma_wrapper(ctx: &CompletionContext<'_>) -> Option<(impl Fn(&str) -> String
         matches!(prev_token_kind, SyntaxKind::COMMA | SyntaxKind::L_PAREN | SyntaxKind::PIPE);
     let leading = if has_leading_comma { "" } else { ", " };
 
-    Some((move |label: &_| (format!("{leading}{label}{trailing}")), param.text_range()))
+    Some((move |label: &_| format!("{leading}{label}{trailing}"), param.text_range()))
 }
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 6e3a76f346a..ea5fb39338b 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
@@ -4,6 +4,7 @@ use std::iter;
 use hir::{ExpandResult, InFile, Semantics, Type, TypeInfo, Variant};
 use ide_db::{RootDatabase, active_parameter::ActiveParameter};
 use itertools::Either;
+use stdx::always;
 use syntax::{
     AstNode, AstToken, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken,
     T, TextRange, TextSize,
@@ -869,8 +870,15 @@ fn classify_name_ref<'db>(
                     return None;
                 }
 
+                let mut receiver_ty = receiver.as_ref().and_then(|it| sema.type_of_expr(it));
+                if receiver_is_ambiguous_float_literal {
+                    // `123.|` is parsed as a float but should actually be an integer.
+                    always!(receiver_ty.as_ref().is_none_or(|receiver_ty| receiver_ty.original.is_float()));
+                    receiver_ty = Some(TypeInfo { original: hir::BuiltinType::i32().ty(sema.db), adjusted: None });
+                }
+
                 let kind = NameRefKind::DotAccess(DotAccess {
-                    receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)),
+                    receiver_ty,
                     kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal },
                     receiver,
                     ctx: DotAccessExprCtx { in_block_expr: is_in_block(field.syntax()), in_breakable: is_in_breakable(field.syntax()) }
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 411902f1117..46a36300459 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
@@ -878,6 +878,7 @@ mod derive {
             expect![[r#"
                 de Clone              macro Clone
                 de Clone, Copy
+                de Debug              macro Debug
                 de Default          macro Default
                 de PartialEq      macro PartialEq
                 de PartialEq, Eq
@@ -900,6 +901,7 @@ mod derive {
             expect![[r#"
                 de Clone     macro Clone
                 de Clone, Copy
+                de Debug     macro Debug
                 de Default macro Default
                 de Eq
                 de Eq, PartialOrd, Ord
@@ -921,6 +923,7 @@ mod derive {
             expect![[r#"
                 de Clone     macro Clone
                 de Clone, Copy
+                de Debug     macro Debug
                 de Default macro Default
                 de Eq
                 de Eq, PartialOrd, Ord
@@ -942,6 +945,7 @@ mod derive {
             expect![[r#"
                 de Clone     macro Clone
                 de Clone, Copy
+                de Debug     macro Debug
                 de Default macro Default
                 de PartialOrd
                 de PartialOrd, Ord
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 b2d18b796f1..33f729f0166 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
@@ -2241,3 +2241,37 @@ fn main() {
     "#,
     );
 }
+
+#[test]
+fn ambiguous_float_literal() {
+    check(
+        r#"
+#![rustc_coherence_is_core]
+
+impl i32 {
+    pub fn int_method(self) {}
+}
+impl f64 {
+    pub fn float_method(self) {}
+}
+
+fn foo() {
+    1.$0
+}
+    "#,
+        expect![[r#"
+            me int_method() fn(self)
+            sn box    Box::new(expr)
+            sn call   function(expr)
+            sn const        const {}
+            sn dbg        dbg!(expr)
+            sn dbgr      dbg!(&expr)
+            sn deref           *expr
+            sn match   match expr {}
+            sn ref             &expr
+            sn refm        &mut expr
+            sn return    return expr
+            sn unsafe      unsafe {}
+        "#]],
+    );
+}
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 fcdf10c8561..179d6693602 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
@@ -550,3 +550,30 @@ fn inside_extern_blocks() {
         "#]],
     )
 }
+
+#[test]
+fn tokens_from_macro() {
+    check_edit(
+        "fn as_ref",
+        r#"
+//- proc_macros: identity
+//- minicore: as_ref
+struct Foo;
+
+#[proc_macros::identity]
+impl<'a> AsRef<&'a i32> for Foo {
+    $0
+}
+    "#,
+        r#"
+struct Foo;
+
+#[proc_macros::identity]
+impl<'a> AsRef<&'a i32> for Foo {
+    fn as_ref(&self) -> &&'a i32 {
+    $0
+}
+}
+    "#,
+    );
+}
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 125e11e9e35..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
@@ -429,18 +429,18 @@ trait Tr<T> {
 impl Tr<$0
     "#,
         expect![[r#"
-            en Enum                        Enum
-            ma makro!(…)     macro_rules! makro
+            en Enum                    Enum
+            ma makro!(…) macro_rules! makro
             md module
-            sp Self dyn Tr<{unknown}> + 'static
-            st Record                    Record
-            st S                              S
-            st Tuple                      Tuple
-            st Unit                        Unit
+            sp Self       dyn Tr<{unknown}>
+            st Record                Record
+            st S                          S
+            st Tuple                  Tuple
+            st Unit                    Unit
             tt Tr
             tt Trait
-            un Union                      Union
-            bt u32                          u32
+            un Union                  Union
+            bt u32                      u32
             kw crate::
             kw self::
         "#]],
diff --git a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
index acde1d665da..e065adb0f0b 100644
--- a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 cov-mark = "2.0.0"
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 994150b1ac4..8e687385086 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,18 @@ impl FamousDefs<'_, '_> {
         self.find_trait("core:convert:AsRef")
     }
 
+    pub fn core_convert_AsMut(&self) -> Option<Trait> {
+        self.find_trait("core:convert:AsMut")
+    }
+
+    pub fn core_borrow_Borrow(&self) -> Option<Trait> {
+        self.find_trait("core:borrow:Borrow")
+    }
+
+    pub fn core_borrow_BorrowMut(&self) -> Option<Trait> {
+        self.find_trait("core:borrow:BorrowMut")
+    }
+
     pub fn core_ops_ControlFlow(&self) -> Option<Enum> {
         self.find_enum("core:ops:ControlFlow")
     }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
index 232648af661..0ab880bcfe7 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
@@ -2,7 +2,10 @@
 
 use crate::helpers::mod_path_to_ast;
 use either::Either;
-use hir::{AsAssocItem, HirDisplay, ImportPathConfig, ModuleDef, SemanticsScope};
+use hir::{
+    AsAssocItem, HirDisplay, HirFileId, ImportPathConfig, ModuleDef, SemanticsScope,
+    prettify_macro_expansion,
+};
 use itertools::Itertools;
 use rustc_hash::FxHashMap;
 use span::Edition;
@@ -136,6 +139,25 @@ impl<'a> PathTransform<'a> {
         }
     }
 
+    fn prettify_target_node(&self, node: SyntaxNode) -> SyntaxNode {
+        match self.target_scope.file_id() {
+            HirFileId::FileId(_) => node,
+            HirFileId::MacroFile(file_id) => {
+                let db = self.target_scope.db;
+                prettify_macro_expansion(
+                    db,
+                    node,
+                    &db.expansion_span_map(file_id),
+                    self.target_scope.module().krate().into(),
+                )
+            }
+        }
+    }
+
+    fn prettify_target_ast<N: AstNode>(&self, node: N) -> N {
+        N::cast(self.prettify_target_node(node.syntax().clone())).unwrap()
+    }
+
     fn build_ctx(&self) -> Ctx<'a> {
         let db = self.source_scope.db;
         let target_module = self.target_scope.module();
@@ -163,7 +185,7 @@ impl<'a> PathTransform<'a> {
             .for_each(|(k, v)| match (k.split(db), v) {
                 (Either::Right(k), Some(TypeOrConst::Either(v))) => {
                     if let Some(ty) = v.ty() {
-                        type_substs.insert(k, ty);
+                        type_substs.insert(k, self.prettify_target_ast(ty));
                     }
                 }
                 (Either::Right(k), None) => {
@@ -178,7 +200,7 @@ impl<'a> PathTransform<'a> {
                 }
                 (Either::Left(k), Some(TypeOrConst::Either(v))) => {
                     if let Some(ty) = v.ty() {
-                        const_substs.insert(k, ty.syntax().clone());
+                        const_substs.insert(k, self.prettify_target_node(ty.syntax().clone()));
                     }
                 }
                 (Either::Left(k), Some(TypeOrConst::Const(v))) => {
@@ -189,7 +211,7 @@ impl<'a> PathTransform<'a> {
                         // and sometimes require slight modifications; see
                         // https://doc.rust-lang.org/reference/statements.html#expression-statements
                         // (default values in curly brackets can cause the same problem)
-                        const_substs.insert(k, expr.syntax().clone());
+                        const_substs.insert(k, self.prettify_target_node(expr.syntax().clone()));
                     }
                 }
                 (Either::Left(k), None) => {
@@ -204,6 +226,7 @@ impl<'a> PathTransform<'a> {
                 }
                 _ => (), // ignore mismatching params
             });
+        // No need to prettify lifetimes, there's nothing to prettify.
         let lifetime_substs: FxHashMap<_, _> = self
             .generic_def
             .into_iter()
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
index 5356614dce5..e6618573e09 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
@@ -272,5 +272,5 @@ fn crate_name(db: &RootDatabase, krate: Crate) -> Symbol {
         .display_name
         .as_deref()
         .cloned()
-        .unwrap_or_else(|| Symbol::integer(salsa::plumbing::AsId::as_id(&krate).as_u32() as usize))
+        .unwrap_or_else(|| Symbol::integer(salsa::plumbing::AsId::as_id(&krate).index() as usize))
 }
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 7d460f72492..4efb83ba323 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
@@ -317,7 +317,7 @@ impl Definition {
             };
             return match def {
                 Some(def) => SearchScope::file_range(
-                    def.as_ref().original_file_range_with_macro_call_body(db),
+                    def.as_ref().original_file_range_with_macro_call_input(db),
                 ),
                 None => SearchScope::single_file(file_id),
             };
@@ -332,7 +332,7 @@ impl Definition {
             };
             return match def {
                 Some(def) => SearchScope::file_range(
-                    def.as_ref().original_file_range_with_macro_call_body(db),
+                    def.as_ref().original_file_range_with_macro_call_input(db),
                 ),
                 None => SearchScope::single_file(file_id),
             };
@@ -341,7 +341,7 @@ impl Definition {
         if let Definition::SelfType(impl_) = self {
             return match impl_.source(db).map(|src| src.syntax().cloned()) {
                 Some(def) => SearchScope::file_range(
-                    def.as_ref().original_file_range_with_macro_call_body(db),
+                    def.as_ref().original_file_range_with_macro_call_input(db),
                 ),
                 None => SearchScope::single_file(file_id),
             };
@@ -360,7 +360,7 @@ impl Definition {
             };
             return match def {
                 Some(def) => SearchScope::file_range(
-                    def.as_ref().original_file_range_with_macro_call_body(db),
+                    def.as_ref().original_file_range_with_macro_call_input(db),
                 ),
                 None => SearchScope::single_file(file_id),
             };
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml
index 96be51e1b26..6f1e66948f4 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 cov-mark = "2.0.0"
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 546512a6cf9..c39e00e178f 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
@@ -242,8 +242,8 @@ macro_rules! outer {
 
 fn f() {
     outer!();
-} //^^^^^^^^ error: leftover tokens
-  //^^^^^^^^ error: Syntax Error in Expansion: expected expression
+} //^^^^^^ error: leftover tokens
+  //^^^^^^ error: Syntax Error in Expansion: expected expression
 "#,
         )
     }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
index 8a5d82b48c0..7da799e0d49 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -66,7 +66,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
     let current_module =
         ctx.sema.scope(d.field_list_parent.to_node(&root).syntax()).map(|it| it.module());
     let range = InFile::new(d.file, d.field_list_parent.text_range())
-        .original_node_file_range_rooted(ctx.sema.db);
+        .original_node_file_range_rooted_opt(ctx.sema.db)?;
 
     let build_text_edit = |new_syntax: &SyntaxNode, old_syntax| {
         let edit = {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
index 0928262d22f..1e80d02926d 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
@@ -239,4 +239,22 @@ impl S {
 "#,
         )
     }
+
+    #[test]
+    fn regression_20155() {
+        check_diagnostics(
+            r#"
+//- minicore: copy, option
+struct Box(i32);
+fn test() {
+    let b = Some(Box(0));
+    || {
+        if let Some(b) = b {
+            let _move = b;
+        }
+    };
+}
+"#,
+        )
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
index 4327b12dce7..fc2648efb40 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
@@ -77,6 +77,7 @@ fn quickfix_for_redundant_assoc_item(
     redundant_item_def: String,
     range: TextRange,
 ) -> Option<Vec<Assist>> {
+    let file_id = d.file_id.file_id()?;
     let add_assoc_item_def = |builder: &mut SourceChangeBuilder| -> Option<()> {
         let db = ctx.sema.db;
         let root = db.parse_or_expand(d.file_id);
@@ -90,12 +91,14 @@ fn quickfix_for_redundant_assoc_item(
         let trait_def = d.trait_.source(db)?.value;
         let l_curly = trait_def.assoc_item_list()?.l_curly_token()?.text_range();
         let where_to_insert =
-            hir::InFile::new(d.file_id, l_curly).original_node_file_range_rooted(db).range;
+            hir::InFile::new(d.file_id, l_curly).original_node_file_range_rooted_opt(db)?;
+        if where_to_insert.file_id != file_id {
+            return None;
+        }
 
-        builder.insert(where_to_insert.end(), redundant_item_def);
+        builder.insert(where_to_insert.range.end(), redundant_item_def);
         Some(())
     };
-    let file_id = d.file_id.file_id()?;
     let mut source_change_builder = SourceChangeBuilder::new(file_id.file_id(ctx.sema.db));
     add_assoc_item_def(&mut source_change_builder)?;
 
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 e2957fcaefb..ac54ac0950f 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
@@ -1171,7 +1171,7 @@ trait B {}
 
 fn test(a: &dyn A) -> &dyn B {
     a
-  //^ error: expected &(dyn B + 'static), found &(dyn A + 'static)
+  //^ error: expected &dyn B, found &dyn A
 }
 "#,
         );
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
index 1f2d671249d..dcca85d4db3 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
@@ -120,8 +120,7 @@ fn assoc_func_fix(
 
         let call = ast::MethodCallExpr::cast(expr.syntax().clone())?;
         let range = InFile::new(expr_ptr.file_id, call.syntax().text_range())
-            .original_node_file_range_rooted(db)
-            .range;
+            .original_node_file_range_rooted_opt(db)?;
 
         let receiver = call.receiver()?;
         let receiver_type = &ctx.sema.type_of_expr(&receiver)?.original;
@@ -174,18 +173,16 @@ fn assoc_func_fix(
 
         let assoc_func_call_expr_string = make::expr_call(assoc_func_path, args).to_string();
 
-        let file_id = ctx.sema.original_range_opt(call.receiver()?.syntax())?.file_id;
-
         Some(Assist {
             id: AssistId::quick_fix("method_call_to_assoc_func_call_fix"),
             label: Label::new(format!(
                 "Use associated func call instead: `{assoc_func_call_expr_string}`"
             )),
             group: None,
-            target: range,
+            target: range.range,
             source_change: Some(SourceChange::from_text_edit(
-                file_id.file_id(ctx.sema.db),
-                TextEdit::replace(range, assoc_func_call_expr_string),
+                range.file_id.file_id(ctx.sema.db),
+                TextEdit::replace(range.range, assoc_func_call_expr_string),
             )),
             command: None,
         })
@@ -300,7 +297,7 @@ macro_rules! m {
 }
 fn main() {
     m!(());
- // ^^^^^^ error: no method `foo` on type `()`
+ // ^^ error: no method `foo` on type `()`
 }
 "#,
         );
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml b/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml
index 1212fa9f9c6..0620bd26fef 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 cov-mark = "2.0.0"
diff --git a/src/tools/rust-analyzer/crates/ide/Cargo.toml b/src/tools/rust-analyzer/crates/ide/Cargo.toml
index 2f8ed88fbb5..06d2776ebe8 100644
--- a/src/tools/rust-analyzer/crates/ide/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 cov-mark = "2.0.0"
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 4b8d07a2533..7a0405939d1 100644
--- a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
@@ -592,7 +592,7 @@ macro_rules! call {
 "#,
             expect!["callee Function FileId(0) 22..37 30..36"],
             expect![[r#"
-                caller Function FileId(0) 38..52 : FileId(0):44..50
+                caller Function FileId(0) 38..43 : FileId(0):44..50
                 caller Function FileId(1) 130..136 130..136 : FileId(0):44..50
                 callee Function FileId(0) 38..52 44..50 : FileId(0):44..50"#]],
             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 2c983287d89..f58202a4213 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -60,7 +60,7 @@ pub(crate) fn rewrite_links(
     let doc = Parser::new_with_broken_link_callback(markdown, MARKDOWN_OPTIONS, Some(&mut cb))
         .into_offset_iter();
 
-    let doc = map_links(doc, |target, title, range| {
+    let doc = map_links(doc, |target, title, range, link_type| {
         // This check is imperfect, there's some overlap between valid intra-doc links
         // and valid URLs so we choose to be too eager to try to resolve what might be
         // a URL.
@@ -78,7 +78,7 @@ pub(crate) fn rewrite_links(
                 .map(|(_, attr_id)| attr_id.is_inner_attr())
                 .unwrap_or(false);
             if let Some((target, title)) =
-                rewrite_intra_doc_link(db, definition, target, title, is_inner_doc)
+                rewrite_intra_doc_link(db, definition, target, title, is_inner_doc, link_type)
             {
                 (None, target, title)
             } else if let Some(target) = rewrite_url_link(db, definition, target) {
@@ -417,6 +417,7 @@ fn rewrite_intra_doc_link(
     target: &str,
     title: &str,
     is_inner_doc: bool,
+    link_type: LinkType,
 ) -> Option<(String, String)> {
     let (link, ns) = parse_intra_doc_link(target);
 
@@ -438,7 +439,21 @@ fn rewrite_intra_doc_link(
     url = url.join(&file).ok()?;
     url.set_fragment(frag);
 
-    Some((url.into(), strip_prefixes_suffixes(title).to_owned()))
+    // We want to strip the keyword prefix from the title, but only if the target is implicitly the same
+    // as the title.
+    let title = match link_type {
+        LinkType::Email
+        | LinkType::Autolink
+        | LinkType::Shortcut
+        | LinkType::Collapsed
+        | LinkType::Reference
+        | LinkType::Inline => title.to_owned(),
+        LinkType::ShortcutUnknown | LinkType::CollapsedUnknown | LinkType::ReferenceUnknown => {
+            strip_prefixes_suffixes(title).to_owned()
+        }
+    };
+
+    Some((url.into(), title))
 }
 
 /// Try to resolve path to local documentation via path-based links (i.e. `../gateway/struct.Shard.html`).
@@ -470,7 +485,7 @@ fn mod_path_of_def(db: &RootDatabase, def: Definition) -> Option<String> {
 /// Rewrites a markdown document, applying 'callback' to each link.
 fn map_links<'e>(
     events: impl Iterator<Item = (Event<'e>, Range<usize>)>,
-    callback: impl Fn(&str, &str, Range<usize>) -> (Option<LinkType>, String, String),
+    callback: impl Fn(&str, &str, Range<usize>, LinkType) -> (Option<LinkType>, String, String),
 ) -> impl Iterator<Item = Event<'e>> {
     let mut in_link = false;
     // holds the origin link target on start event and the rewritten one on end event
@@ -497,7 +512,7 @@ fn map_links<'e>(
         }
         Event::Text(s) if in_link => {
             let (link_type, link_target_s, link_name) =
-                callback(&end_link_target.take().unwrap(), &s, range);
+                callback(&end_link_target.take().unwrap(), &s, range, end_link_type.unwrap());
             end_link_target = Some(CowStr::Boxed(link_target_s.into()));
             if !matches!(end_link_type, Some(LinkType::Autolink)) {
                 end_link_type = link_type;
@@ -506,7 +521,7 @@ fn map_links<'e>(
         }
         Event::Code(s) if in_link => {
             let (link_type, link_target_s, link_name) =
-                callback(&end_link_target.take().unwrap(), &s, range);
+                callback(&end_link_target.take().unwrap(), &s, range, end_link_type.unwrap());
             end_link_target = Some(CowStr::Boxed(link_target_s.into()));
             if !matches!(end_link_type, Some(LinkType::Autolink)) {
                 end_link_type = link_type;
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 347da4e85b4..6820f99facf 100644
--- a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
@@ -329,7 +329,7 @@ macro_rules! mcexp {
 #[deprecated]
 fn obsolete() {}
 
-#[deprecated(note = "for awhile")]
+#[deprecated(note = "for a while")]
 fn very_obsolete() {}
 
 // region: Some region name
@@ -608,8 +608,8 @@ fn let_statements() {
                     StructureNode {
                         parent: None,
                         label: "very_obsolete",
-                        navigation_range: 511..524,
-                        node_range: 473..529,
+                        navigation_range: 512..525,
+                        node_range: 473..530,
                         kind: SymbolKind(
                             Function,
                         ),
@@ -621,8 +621,8 @@ fn let_statements() {
                     StructureNode {
                         parent: None,
                         label: "Some region name",
-                        navigation_range: 531..558,
-                        node_range: 531..558,
+                        navigation_range: 532..559,
+                        node_range: 532..559,
                         kind: Region,
                         detail: None,
                         deprecated: false,
@@ -630,8 +630,8 @@ fn let_statements() {
                     StructureNode {
                         parent: None,
                         label: "m",
-                        navigation_range: 598..599,
-                        node_range: 573..636,
+                        navigation_range: 599..600,
+                        node_range: 574..637,
                         kind: SymbolKind(
                             Module,
                         ),
@@ -643,8 +643,8 @@ fn let_statements() {
                             22,
                         ),
                         label: "dontpanic",
-                        navigation_range: 573..593,
-                        node_range: 573..593,
+                        navigation_range: 574..594,
+                        node_range: 574..594,
                         kind: Region,
                         detail: None,
                         deprecated: false,
@@ -654,8 +654,8 @@ fn let_statements() {
                             22,
                         ),
                         label: "f",
-                        navigation_range: 605..606,
-                        node_range: 602..611,
+                        navigation_range: 606..607,
+                        node_range: 603..612,
                         kind: SymbolKind(
                             Function,
                         ),
@@ -669,8 +669,8 @@ fn let_statements() {
                             22,
                         ),
                         label: "g",
-                        navigation_range: 628..629,
-                        node_range: 612..634,
+                        navigation_range: 629..630,
+                        node_range: 613..635,
                         kind: SymbolKind(
                             Function,
                         ),
@@ -682,8 +682,8 @@ fn let_statements() {
                     StructureNode {
                         parent: None,
                         label: "extern \"C\"",
-                        navigation_range: 638..648,
-                        node_range: 638..651,
+                        navigation_range: 639..649,
+                        node_range: 639..652,
                         kind: ExternBlock,
                         detail: None,
                         deprecated: false,
@@ -691,8 +691,8 @@ fn let_statements() {
                     StructureNode {
                         parent: None,
                         label: "let_statements",
-                        navigation_range: 656..670,
-                        node_range: 653..813,
+                        navigation_range: 657..671,
+                        node_range: 654..814,
                         kind: SymbolKind(
                             Function,
                         ),
@@ -706,8 +706,8 @@ fn let_statements() {
                             27,
                         ),
                         label: "x",
-                        navigation_range: 683..684,
-                        node_range: 679..690,
+                        navigation_range: 684..685,
+                        node_range: 680..691,
                         kind: SymbolKind(
                             Local,
                         ),
@@ -719,8 +719,8 @@ fn let_statements() {
                             27,
                         ),
                         label: "mut y",
-                        navigation_range: 699..704,
-                        node_range: 695..709,
+                        navigation_range: 700..705,
+                        node_range: 696..710,
                         kind: SymbolKind(
                             Local,
                         ),
@@ -732,8 +732,8 @@ fn let_statements() {
                             27,
                         ),
                         label: "Foo { .. }",
-                        navigation_range: 718..740,
-                        node_range: 714..753,
+                        navigation_range: 719..741,
+                        node_range: 715..754,
                         kind: SymbolKind(
                             Local,
                         ),
@@ -745,8 +745,8 @@ fn let_statements() {
                             27,
                         ),
                         label: "_",
-                        navigation_range: 803..804,
-                        node_range: 799..811,
+                        navigation_range: 804..805,
+                        node_range: 800..812,
                         kind: SymbolKind(
                             Local,
                         ),
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 194e8c968f7..9bd8504733a 100755
--- a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs
@@ -2,7 +2,7 @@ use ide_db::{FxHashSet, syntax_helpers::node_ext::vis_eq};
 use syntax::{
     Direction, NodeOrToken, SourceFile,
     SyntaxKind::{self, *},
-    TextRange, TextSize,
+    SyntaxNode, TextRange, TextSize,
     ast::{self, AstNode, AstToken},
     match_ast,
 };
@@ -16,16 +16,21 @@ const REGION_END: &str = "// endregion";
 pub enum FoldKind {
     Comment,
     Imports,
-    Mods,
+    Region,
     Block,
     ArgList,
-    Region,
-    Consts,
-    Statics,
     Array,
     WhereClause,
     ReturnType,
     MatchArm,
+    // region: item runs
+    Modules,
+    Consts,
+    Statics,
+    TypeAliases,
+    TraitAliases,
+    ExternCrates,
+    // endregion: item runs
 }
 
 #[derive(Debug)]
@@ -41,10 +46,7 @@ pub struct Fold {
 pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
     let mut res = vec![];
     let mut visited_comments = FxHashSet::default();
-    let mut visited_imports = FxHashSet::default();
-    let mut visited_mods = FxHashSet::default();
-    let mut visited_consts = FxHashSet::default();
-    let mut visited_statics = FxHashSet::default();
+    let mut visited_nodes = FxHashSet::default();
 
     // regions can be nested, here is a LIFO buffer
     let mut region_starts: Vec<TextSize> = vec![];
@@ -93,30 +95,40 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
                             if module.item_list().is_none() {
                                 if let Some(range) = contiguous_range_for_item_group(
                                     module,
-                                    &mut visited_mods,
+                                    &mut visited_nodes,
                                 ) {
-                                    res.push(Fold { range, kind: FoldKind::Mods })
+                                    res.push(Fold { range, kind: FoldKind::Modules })
                                 }
                             }
                         },
                         ast::Use(use_) => {
-                            if let Some(range) = contiguous_range_for_item_group(use_, &mut visited_imports) {
+                            if let Some(range) = contiguous_range_for_item_group(use_, &mut visited_nodes) {
                                 res.push(Fold { range, kind: FoldKind::Imports })
                             }
                         },
                         ast::Const(konst) => {
-                            if let Some(range) = contiguous_range_for_item_group(konst, &mut visited_consts) {
+                            if let Some(range) = contiguous_range_for_item_group(konst, &mut visited_nodes) {
                                 res.push(Fold { range, kind: FoldKind::Consts })
                             }
                         },
                         ast::Static(statik) => {
-                            if let Some(range) = contiguous_range_for_item_group(statik, &mut visited_statics) {
+                            if let Some(range) = contiguous_range_for_item_group(statik, &mut visited_nodes) {
                                 res.push(Fold { range, kind: FoldKind::Statics })
                             }
                         },
-                        ast::WhereClause(where_clause) => {
-                            if let Some(range) = fold_range_for_where_clause(where_clause) {
-                                res.push(Fold { range, kind: FoldKind::WhereClause })
+                        ast::TypeAlias(alias) => {
+                            if let Some(range) = contiguous_range_for_item_group(alias, &mut visited_nodes) {
+                                res.push(Fold { range, kind: FoldKind::TypeAliases })
+                            }
+                        },
+                        ast::TraitAlias(alias) => {
+                            if let Some(range) = contiguous_range_for_item_group(alias, &mut visited_nodes) {
+                                res.push(Fold { range, kind: FoldKind::TraitAliases })
+                            }
+                        },
+                        ast::ExternCrate(extern_crate) => {
+                            if let Some(range) = contiguous_range_for_item_group(extern_crate, &mut visited_nodes) {
+                                res.push(Fold { range, kind: FoldKind::ExternCrates })
                             }
                         },
                         ast::MatchArm(match_arm) => {
@@ -137,9 +149,10 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
 fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
     match kind {
         COMMENT => Some(FoldKind::Comment),
-        ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList),
+        ARG_LIST | PARAM_LIST | GENERIC_ARG_LIST | GENERIC_PARAM_LIST => Some(FoldKind::ArgList),
         ARRAY_EXPR => Some(FoldKind::Array),
         RET_TYPE => Some(FoldKind::ReturnType),
+        WHERE_CLAUSE => Some(FoldKind::WhereClause),
         ASSOC_ITEM_LIST
         | RECORD_FIELD_LIST
         | RECORD_PAT_FIELD_LIST
@@ -155,11 +168,14 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
     }
 }
 
-fn contiguous_range_for_item_group<N>(first: N, visited: &mut FxHashSet<N>) -> Option<TextRange>
+fn contiguous_range_for_item_group<N>(
+    first: N,
+    visited: &mut FxHashSet<SyntaxNode>,
+) -> Option<TextRange>
 where
     N: ast::HasVisibility + Clone + Hash + Eq,
 {
-    if !visited.insert(first.clone()) {
+    if !visited.insert(first.syntax().clone()) {
         return None;
     }
 
@@ -183,7 +199,7 @@ where
         if let Some(next) = N::cast(node) {
             let next_vis = next.visibility();
             if eq_visibility(next_vis.clone(), last_vis) {
-                visited.insert(next.clone());
+                visited.insert(next.syntax().clone());
                 last_vis = next_vis;
                 last = next;
                 continue;
@@ -259,18 +275,6 @@ fn contiguous_range_for_comment(
     }
 }
 
-fn fold_range_for_where_clause(where_clause: ast::WhereClause) -> Option<TextRange> {
-    let first_where_pred = where_clause.predicates().next();
-    let last_where_pred = where_clause.predicates().last();
-
-    if first_where_pred != last_where_pred {
-        let start = where_clause.where_token()?.text_range().end();
-        let end = where_clause.syntax().text_range().end();
-        return Some(TextRange::new(start, end));
-    }
-    None
-}
-
 fn fold_range_for_multiline_match_arm(match_arm: ast::MatchArm) -> Option<TextRange> {
     if fold_kind(match_arm.expr()?.syntax().kind()).is_some() {
         None
@@ -307,16 +311,19 @@ mod tests {
             let kind = match fold.kind {
                 FoldKind::Comment => "comment",
                 FoldKind::Imports => "imports",
-                FoldKind::Mods => "mods",
+                FoldKind::Modules => "mods",
                 FoldKind::Block => "block",
                 FoldKind::ArgList => "arglist",
                 FoldKind::Region => "region",
                 FoldKind::Consts => "consts",
                 FoldKind::Statics => "statics",
+                FoldKind::TypeAliases => "typealiases",
                 FoldKind::Array => "array",
                 FoldKind::WhereClause => "whereclause",
                 FoldKind::ReturnType => "returntype",
                 FoldKind::MatchArm => "matcharm",
+                FoldKind::TraitAliases => "traitaliases",
+                FoldKind::ExternCrates => "externcrates",
             };
             assert_eq!(kind, &attr.unwrap());
         }
@@ -594,19 +601,18 @@ static SECOND_STATIC: &str = "second";</fold>
 
     #[test]
     fn fold_where_clause() {
-        // fold multi-line and don't fold single line.
         check(
             r#"
 fn foo()
-where<fold whereclause>
+<fold whereclause>where
     A: Foo,
     B: Foo,
     C: Foo,
     D: Foo,</fold> {}
 
 fn bar()
-where
-    A: Bar, {}
+<fold whereclause>where
+    A: Bar,</fold> {}
 "#,
         )
     }
@@ -624,4 +630,16 @@ fn bar() -> (bool, bool) { (true, true) }
 "#,
         )
     }
+
+    #[test]
+    fn fold_generics() {
+        check(
+            r#"
+type Foo<T, U> = foo<fold arglist><
+    T,
+    U,
+></fold>;
+"#,
+        )
+    }
 }
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 574803fb9e8..29fc68bb50f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -291,13 +291,14 @@ fn handle_control_flow_keywords(
     token: &SyntaxToken,
 ) -> Option<Vec<NavigationTarget>> {
     match token.kind() {
-        // For `fn` / `loop` / `while` / `for` / `async`, return the keyword it self,
+        // For `fn` / `loop` / `while` / `for` / `async` / `match`, return the keyword it self,
         // so that VSCode will find the references when using `ctrl + click`
         T![fn] | T![async] | T![try] | T![return] => nav_for_exit_points(sema, token),
         T![loop] | T![while] | T![break] | T![continue] => nav_for_break_points(sema, token),
         T![for] if token.parent().and_then(ast::ForExpr::cast).is_some() => {
             nav_for_break_points(sema, token)
         }
+        T![match] | T![=>] | T![if] => nav_for_branch_exit_points(sema, token),
         _ => None,
     }
 }
@@ -407,6 +408,91 @@ fn nav_for_exit_points(
     Some(navs)
 }
 
+pub(crate) fn find_branch_root(
+    sema: &Semantics<'_, RootDatabase>,
+    token: &SyntaxToken,
+) -> Vec<SyntaxNode> {
+    let find_nodes = |node_filter: fn(SyntaxNode) -> Option<SyntaxNode>| {
+        sema.descend_into_macros(token.clone())
+            .into_iter()
+            .filter_map(|token| node_filter(token.parent()?))
+            .collect_vec()
+    };
+
+    match token.kind() {
+        T![match] => find_nodes(|node| Some(ast::MatchExpr::cast(node)?.syntax().clone())),
+        T![=>] => find_nodes(|node| Some(ast::MatchArm::cast(node)?.syntax().clone())),
+        T![if] => find_nodes(|node| {
+            let if_expr = ast::IfExpr::cast(node)?;
+
+            let root_if = iter::successors(Some(if_expr.clone()), |if_expr| {
+                let parent_if = if_expr.syntax().parent().and_then(ast::IfExpr::cast)?;
+                let ast::ElseBranch::IfExpr(else_branch) = parent_if.else_branch()? else {
+                    return None;
+                };
+
+                (else_branch.syntax() == if_expr.syntax()).then_some(parent_if)
+            })
+            .last()?;
+
+            Some(root_if.syntax().clone())
+        }),
+        _ => vec![],
+    }
+}
+
+fn nav_for_branch_exit_points(
+    sema: &Semantics<'_, RootDatabase>,
+    token: &SyntaxToken,
+) -> Option<Vec<NavigationTarget>> {
+    let db = sema.db;
+
+    let navs = match token.kind() {
+        T![match] => find_branch_root(sema, token)
+            .into_iter()
+            .filter_map(|node| {
+                let file_id = sema.hir_file_for(&node);
+                let match_expr = ast::MatchExpr::cast(node)?;
+                let focus_range = match_expr.match_token()?.text_range();
+                let match_expr_in_file = InFile::new(file_id, match_expr.into());
+                Some(expr_to_nav(db, match_expr_in_file, Some(focus_range)))
+            })
+            .flatten()
+            .collect_vec(),
+
+        T![=>] => find_branch_root(sema, token)
+            .into_iter()
+            .filter_map(|node| {
+                let match_arm = ast::MatchArm::cast(node)?;
+                let match_expr = sema
+                    .ancestors_with_macros(match_arm.syntax().clone())
+                    .find_map(ast::MatchExpr::cast)?;
+                let file_id = sema.hir_file_for(match_expr.syntax());
+                let focus_range = match_arm.fat_arrow_token()?.text_range();
+                let match_expr_in_file = InFile::new(file_id, match_expr.into());
+                Some(expr_to_nav(db, match_expr_in_file, Some(focus_range)))
+            })
+            .flatten()
+            .collect_vec(),
+
+        T![if] => find_branch_root(sema, token)
+            .into_iter()
+            .filter_map(|node| {
+                let file_id = sema.hir_file_for(&node);
+                let if_expr = ast::IfExpr::cast(node)?;
+                let focus_range = if_expr.if_token()?.text_range();
+                let if_expr_in_file = InFile::new(file_id, if_expr.into());
+                Some(expr_to_nav(db, if_expr_in_file, Some(focus_range)))
+            })
+            .flatten()
+            .collect_vec(),
+
+        _ => return Some(Vec::new()),
+    };
+
+    Some(navs)
+}
+
 pub(crate) fn find_loops(
     sema: &Semantics<'_, RootDatabase>,
     token: &SyntaxToken,
@@ -996,7 +1082,7 @@ macro_rules! define_fn {
 }
 
   define_fn!();
-//^^^^^^^^^^^^^
+//^^^^^^^^^^
 fn bar() {
    $0foo();
 }
@@ -3142,7 +3228,7 @@ mod bar {
     use crate::m;
 
     m!();
- // ^^^^^
+ // ^^
 
     fn qux() {
         Foo$0;
@@ -3614,4 +3700,227 @@ fn foo() {
         "#,
         );
     }
+
+    #[test]
+    fn goto_def_for_match_keyword() {
+        check(
+            r#"
+fn main() {
+    match$0 0 {
+ // ^^^^^
+        0 => {},
+        _ => {},
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_def_for_match_arm_fat_arrow() {
+        check(
+            r#"
+fn main() {
+    match 0 {
+        0 =>$0 {},
+       // ^^
+        _ => {},
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_def_for_if_keyword() {
+        check(
+            r#"
+fn main() {
+    if$0 true {
+ // ^^
+        ()
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_def_for_match_nested_in_if() {
+        check(
+            r#"
+fn main() {
+    if true {
+        match$0 0 {
+     // ^^^^^
+            0 => {},
+            _ => {},
+        }
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_def_for_multiple_match_expressions() {
+        check(
+            r#"
+fn main() {
+    match 0 {
+        0 => {},
+        _ => {},
+    };
+
+    match$0 1 {
+ // ^^^^^
+        1 => {},
+        _ => {},
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_def_for_nested_match_expressions() {
+        check(
+            r#"
+fn main() {
+    match 0 {
+        0 => match$0 1 {
+          // ^^^^^
+            1 => {},
+            _ => {},
+        },
+        _ => {},
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_def_for_if_else_chains() {
+        check(
+            r#"
+fn main() {
+    if true {
+ // ^^
+        ()
+    } else if$0 false {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_def_for_match_with_guards() {
+        check(
+            r#"
+fn main() {
+    match 42 {
+        x if x > 0 =>$0 {},
+                // ^^
+        _ => {},
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_def_for_match_with_macro_arm() {
+        check(
+            r#"
+macro_rules! arm {
+    () => { 0 => {} };
+}
+
+fn main() {
+    match$0 0 {
+ // ^^^^^
+        arm!(),
+        _ => {},
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_const_from_match_pat_with_tuple_struct() {
+        check(
+            r#"
+struct Tag(u8);
+struct Path {}
+
+const Path: u8 = 0;
+   // ^^^^
+fn main() {
+    match Tag(Path) {
+        Tag(Path$0) => {}
+        _ => {}
+    }
+}
+
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_const_from_match_pat() {
+        check(
+            r#"
+type T1 = u8;
+const T1: u8 = 0;
+   // ^^
+fn main() {
+    let x = 0;
+    match x {
+        T1$0 => {}
+        _ => {}
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_struct_from_match_pat() {
+        check(
+            r#"
+struct T1;
+    // ^^
+fn main() {
+    let x = 0;
+    match x {
+        T1$0 => {}
+        _ => {}
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn no_goto_trait_from_match_pat() {
+        check(
+            r#"
+trait T1 {}
+fn main() {
+    let x = 0;
+    match x {
+        T1$0 => {}
+     // ^^
+        _ => {}
+    }
+}
+"#,
+        );
+    }
 }
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 86d72fefe05..b80e81d39c6 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
@@ -70,11 +70,10 @@ pub(crate) fn goto_type_definition(
     }
 
     let range = token.text_range();
-    sema.descend_into_macros_no_opaque(token,false)
+    sema.descend_into_macros_no_opaque(token, false)
         .into_iter()
         .filter_map(|token| {
-            sema
-                .token_ancestors_with_macros(token.value)
+            sema.token_ancestors_with_macros(token.value)
                 // When `token` is within a macro call, we can't determine its type. Don't continue
                 // this traversal because otherwise we'll end up returning the type of *that* macro
                 // call, which is not what we want in general.
@@ -103,7 +102,6 @@ pub(crate) fn goto_type_definition(
                             _ => return None,
                         }
                     };
-
                     Some(ty)
                 })
         })
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 aa947921a9b..356bd69aa44 100644
--- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
@@ -37,8 +37,11 @@ pub struct HighlightRelatedConfig {
     pub break_points: bool,
     pub closure_captures: bool,
     pub yield_points: bool,
+    pub branch_exit_points: bool,
 }
 
+type HighlightMap = FxHashMap<EditionedFileId, FxHashSet<HighlightedRange>>;
+
 // Feature: Highlight Related
 //
 // Highlights constructs related to the thing under the cursor:
@@ -64,7 +67,7 @@ pub(crate) fn highlight_related(
 
     let token = pick_best_token(syntax.token_at_offset(offset), |kind| match kind {
         T![?] => 4, // prefer `?` when the cursor is sandwiched like in `await$0?`
-        T![->] => 4,
+        T![->] | T![=>] => 4,
         kind if kind.is_keyword(file_id.edition(sema.db)) => 3,
         IDENT | INT_NUMBER => 2,
         T![|] => 1,
@@ -78,6 +81,9 @@ pub(crate) fn highlight_related(
         T![fn] | T![return] | T![->] if config.exit_points => {
             highlight_exit_points(sema, token).remove(&file_id)
         }
+        T![match] | T![=>] | T![if] if config.branch_exit_points => {
+            highlight_branch_exit_points(sema, token).remove(&file_id)
+        }
         T![await] | T![async] if config.yield_points => {
             highlight_yield_points(sema, token).remove(&file_id)
         }
@@ -300,11 +306,93 @@ fn highlight_references(
     if res.is_empty() { None } else { Some(res.into_iter().collect()) }
 }
 
+pub(crate) fn highlight_branch_exit_points(
+    sema: &Semantics<'_, RootDatabase>,
+    token: SyntaxToken,
+) -> FxHashMap<EditionedFileId, Vec<HighlightedRange>> {
+    let mut highlights: HighlightMap = FxHashMap::default();
+
+    let push_to_highlights = |file_id, range, highlights: &mut HighlightMap| {
+        if let Some(FileRange { file_id, range }) = original_frange(sema.db, file_id, range) {
+            let hrange = HighlightedRange { category: ReferenceCategory::empty(), range };
+            highlights.entry(file_id).or_default().insert(hrange);
+        }
+    };
+
+    let push_tail_expr = |tail: Option<ast::Expr>, highlights: &mut HighlightMap| {
+        let Some(tail) = tail else {
+            return;
+        };
+
+        for_each_tail_expr(&tail, &mut |tail| {
+            let file_id = sema.hir_file_for(tail.syntax());
+            let range = tail.syntax().text_range();
+            push_to_highlights(file_id, Some(range), highlights);
+        });
+    };
+
+    let nodes = goto_definition::find_branch_root(sema, &token).into_iter();
+    match token.kind() {
+        T![match] => {
+            for match_expr in nodes.filter_map(ast::MatchExpr::cast) {
+                let file_id = sema.hir_file_for(match_expr.syntax());
+                let range = match_expr.match_token().map(|token| token.text_range());
+                push_to_highlights(file_id, range, &mut highlights);
+
+                let Some(arm_list) = match_expr.match_arm_list() else {
+                    continue;
+                };
+                for arm in arm_list.arms() {
+                    push_tail_expr(arm.expr(), &mut highlights);
+                }
+            }
+        }
+        T![=>] => {
+            for arm in nodes.filter_map(ast::MatchArm::cast) {
+                let file_id = sema.hir_file_for(arm.syntax());
+                let range = arm.fat_arrow_token().map(|token| token.text_range());
+                push_to_highlights(file_id, range, &mut highlights);
+
+                push_tail_expr(arm.expr(), &mut highlights);
+            }
+        }
+        T![if] => {
+            for mut if_to_process in nodes.map(ast::IfExpr::cast) {
+                while let Some(cur_if) = if_to_process.take() {
+                    let file_id = sema.hir_file_for(cur_if.syntax());
+
+                    let if_kw_range = cur_if.if_token().map(|token| token.text_range());
+                    push_to_highlights(file_id, if_kw_range, &mut highlights);
+
+                    if let Some(then_block) = cur_if.then_branch() {
+                        push_tail_expr(Some(then_block.into()), &mut highlights);
+                    }
+
+                    match cur_if.else_branch() {
+                        Some(ast::ElseBranch::Block(else_block)) => {
+                            push_tail_expr(Some(else_block.into()), &mut highlights);
+                            if_to_process = None;
+                        }
+                        Some(ast::ElseBranch::IfExpr(nested_if)) => if_to_process = Some(nested_if),
+                        None => if_to_process = None,
+                    }
+                }
+            }
+        }
+        _ => {}
+    }
+
+    highlights
+        .into_iter()
+        .map(|(file_id, ranges)| (file_id, ranges.into_iter().collect()))
+        .collect()
+}
+
 fn hl_exit_points(
     sema: &Semantics<'_, RootDatabase>,
     def_token: Option<SyntaxToken>,
     body: ast::Expr,
-) -> Option<FxHashMap<EditionedFileId, FxHashSet<HighlightedRange>>> {
+) -> Option<HighlightMap> {
     let mut highlights: FxHashMap<EditionedFileId, FxHashSet<_>> = FxHashMap::default();
 
     let mut push_to_highlights = |file_id, range| {
@@ -411,7 +499,7 @@ pub(crate) fn highlight_break_points(
         loop_token: Option<SyntaxToken>,
         label: Option<ast::Label>,
         expr: ast::Expr,
-    ) -> Option<FxHashMap<EditionedFileId, FxHashSet<HighlightedRange>>> {
+    ) -> Option<HighlightMap> {
         let mut highlights: FxHashMap<EditionedFileId, FxHashSet<_>> = FxHashMap::default();
 
         let mut push_to_highlights = |file_id, range| {
@@ -504,7 +592,7 @@ pub(crate) fn highlight_yield_points(
         sema: &Semantics<'_, RootDatabase>,
         async_token: Option<SyntaxToken>,
         body: Option<ast::Expr>,
-    ) -> Option<FxHashMap<EditionedFileId, FxHashSet<HighlightedRange>>> {
+    ) -> Option<HighlightMap> {
         let mut highlights: FxHashMap<EditionedFileId, FxHashSet<_>> = FxHashMap::default();
 
         let mut push_to_highlights = |file_id, range| {
@@ -597,10 +685,7 @@ fn original_frange(
     InFile::new(file_id, text_range?).original_node_file_range_opt(db).map(|(frange, _)| frange)
 }
 
-fn merge_map(
-    res: &mut FxHashMap<EditionedFileId, FxHashSet<HighlightedRange>>,
-    new: Option<FxHashMap<EditionedFileId, FxHashSet<HighlightedRange>>>,
-) {
+fn merge_map(res: &mut HighlightMap, new: Option<HighlightMap>) {
     let Some(new) = new else {
         return;
     };
@@ -750,6 +835,7 @@ mod tests {
         references: true,
         closure_captures: true,
         yield_points: true,
+        branch_exit_points: true,
     };
 
     #[track_caller]
@@ -2135,6 +2221,62 @@ fn main() {
     }
 
     #[test]
+    fn nested_match() {
+        check(
+            r#"
+fn main() {
+    match$0 0 {
+ // ^^^^^
+        0 => match 1 {
+            1 => 2,
+              // ^
+            _ => 3,
+              // ^
+        },
+        _ => 4,
+          // ^
+    }
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn single_arm_highlight() {
+        check(
+            r#"
+fn main() {
+    match 0 {
+        0 =>$0 {
+       // ^^
+            let x = 1;
+            x
+         // ^
+        }
+        _ => 2,
+    }
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn no_branches_when_disabled() {
+        let config = HighlightRelatedConfig { branch_exit_points: false, ..ENABLED_CONFIG };
+        check_with_config(
+            r#"
+fn main() {
+    match$0 0 {
+        0 => 1,
+        _ => 2,
+    }
+}
+"#,
+            config,
+        );
+    }
+
+    #[test]
     fn asm() {
         check(
             r#"
@@ -2165,6 +2307,200 @@ pub unsafe fn bootstrap() -> ! {
     }
 
     #[test]
+    fn complex_arms_highlight() {
+        check(
+            r#"
+fn calculate(n: i32) -> i32 { n * 2 }
+
+fn main() {
+    match$0 Some(1) {
+ // ^^^^^
+        Some(x) => match x {
+            0 => { let y = x; y },
+                           // ^
+            1 => calculate(x),
+               //^^^^^^^^^^^^
+            _ => (|| 6)(),
+              // ^^^^^^^^
+        },
+        None => loop {
+            break 5;
+         // ^^^^^^^
+        },
+    }
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn match_in_macro_highlight() {
+        check(
+            r#"
+macro_rules! M {
+    ($e:expr) => { $e };
+}
+
+fn main() {
+    M!{
+        match$0 Some(1) {
+     // ^^^^^
+            Some(x) => x,
+                    // ^
+            None => 0,
+                 // ^
+        }
+    }
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn match_in_macro_highlight_2() {
+        check(
+            r#"
+macro_rules! match_ast {
+    (match $node:ident { $($tt:tt)* }) => { $crate::match_ast!(match ($node) { $($tt)* }) };
+
+    (match ($node:expr) {
+        $( $( $path:ident )::+ ($it:pat) => $res:expr, )*
+        _ => $catch_all:expr $(,)?
+    }) => {{
+        $( if let Some($it) = $($path::)+cast($node.clone()) { $res } else )*
+        { $catch_all }
+    }};
+}
+
+fn main() {
+    match_ast! {
+        match$0 Some(1) {
+            Some(x) => x,
+        }
+    }
+}
+            "#,
+        );
+    }
+
+    #[test]
+    fn nested_if_else() {
+        check(
+            r#"
+fn main() {
+    if$0 true {
+ // ^^
+        if false {
+            1
+         // ^
+        } else {
+            2
+         // ^
+        }
+    } else {
+        3
+     // ^
+    }
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn if_else_if_highlight() {
+        check(
+            r#"
+fn main() {
+    if$0 true {
+ // ^^
+        1
+     // ^
+    } else if false {
+        // ^^
+        2
+     // ^
+    } else {
+        3
+     // ^
+    }
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn complex_if_branches() {
+        check(
+            r#"
+fn calculate(n: i32) -> i32 { n * 2 }
+
+fn main() {
+    if$0 true {
+ // ^^
+        let x = 5;
+        calculate(x)
+     // ^^^^^^^^^^^^
+    } else if false {
+        // ^^
+        (|| 10)()
+     // ^^^^^^^^^
+    } else {
+        loop {
+            break 15;
+         // ^^^^^^^^
+        }
+    }
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn if_in_macro_highlight() {
+        check(
+            r#"
+macro_rules! M {
+    ($e:expr) => { $e };
+}
+
+fn main() {
+    M!{
+        if$0 true {
+     // ^^
+            5
+         // ^
+        } else {
+            10
+         // ^^
+        }
+    }
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn match_in_macro() {
+        // We should not highlight the outer `match` expression.
+        check(
+            r#"
+macro_rules! M {
+    (match) => { 1 };
+}
+
+fn main() {
+    match Some(1) {
+        Some(x) => x,
+        None => {
+            M!(match$0)
+        }
+    }
+}
+            "#,
+        )
+    }
+
+    #[test]
     fn labeled_block_tail_expr() {
         check(
             r#"
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 a281a491525..f63499aa0fd 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -10927,3 +10927,34 @@ fn main() {
         "#]],
     );
 }
+
+#[test]
+fn keyword_inside_link() {
+    check(
+        r#"
+enum Foo {
+    MacroExpansion,
+}
+
+/// I return a [macro expansion](Foo::MacroExpansion).
+fn bar$0() -> Foo {
+    Foo::MacroExpansion
+}
+    "#,
+        expect![[r#"
+            *bar*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            fn bar() -> Foo
+            ```
+
+            ---
+
+            I return a [macro expansion](https://docs.rs/ra_test_fixture/*/ra_test_fixture/enum.Foo.html#variant.MacroExpansion).
+        "#]],
+    );
+}
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 f2844a2eaa6..49b43fc37f2 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
@@ -109,50 +109,90 @@ pub(super) fn hints(
         }
         has_adjustments = true;
 
-        // FIXME: Add some nicer tooltips to each of these
-        let (text, coercion) = match kind {
+        let (text, coercion, detailed_tooltip) = match kind {
             Adjust::NeverToAny if config.adjustment_hints == AdjustmentHints::Always => {
                 allow_edit = false;
-                ("<never-to-any>", "never to any")
-            }
-            Adjust::Deref(None) => ("*", "dereference"),
-            Adjust::Deref(Some(OverloadedDeref(Mutability::Shared))) => {
-                ("*", "`Deref` dereference")
-            }
-            Adjust::Deref(Some(OverloadedDeref(Mutability::Mut))) => {
-                ("*", "`DerefMut` dereference")
-            }
-            Adjust::Borrow(AutoBorrow::Ref(Mutability::Shared)) => ("&", "borrow"),
-            Adjust::Borrow(AutoBorrow::Ref(Mutability::Mut)) => ("&mut ", "unique borrow"),
-            Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Shared)) => {
-                ("&raw const ", "const pointer borrow")
-            }
-            Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Mut)) => {
-                ("&raw mut ", "mut pointer borrow")
+                (
+                    "<never-to-any>",
+                    "never to any",
+                    "Coerces the never type `!` into any other type. This happens in code paths that never return, like after `panic!()` or `return`.",
+                )
             }
+            Adjust::Deref(None) => (
+                "*",
+                "dereference",
+                "Built-in dereference of a reference to access the underlying value. The compiler inserts `*` to get the value from `&T`.",
+            ),
+            Adjust::Deref(Some(OverloadedDeref(Mutability::Shared))) => (
+                "*",
+                "`Deref` dereference",
+                "Dereference via the `Deref` trait. Used for types like `Box<T>` or `Rc<T>` so they act like plain `T`.",
+            ),
+            Adjust::Deref(Some(OverloadedDeref(Mutability::Mut))) => (
+                "*",
+                "`DerefMut` dereference",
+                "Mutable dereference using the `DerefMut` trait. Enables smart pointers to give mutable access to their inner values.",
+            ),
+            Adjust::Borrow(AutoBorrow::Ref(Mutability::Shared)) => (
+                "&",
+                "shared borrow",
+                "Inserts `&` to create a shared reference. Lets you use a value without moving or cloning it.",
+            ),
+            Adjust::Borrow(AutoBorrow::Ref(Mutability::Mut)) => (
+                "&mut ",
+                "mutable borrow",
+                "Inserts `&mut` to create a unique, mutable reference. Lets you modify a value without taking ownership.",
+            ),
+            Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Shared)) => (
+                "&raw const ",
+                "const raw pointer",
+                "Converts a reference to a raw const pointer `*const T`. Often used when working with FFI or unsafe code.",
+            ),
+            Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Mut)) => (
+                "&raw mut ",
+                "mut raw pointer",
+                "Converts a mutable reference to a raw mutable pointer `*mut T`. Allows mutation in unsafe contexts.",
+            ),
             // some of these could be represented via `as` casts, but that's not too nice and
             // handling everything as a prefix expr makes the `(` and `)` insertion easier
             Adjust::Pointer(cast) if config.adjustment_hints == AdjustmentHints::Always => {
                 allow_edit = false;
                 match cast {
-                    PointerCast::ReifyFnPointer => {
-                        ("<fn-item-to-fn-pointer>", "fn item to fn pointer")
-                    }
+                    PointerCast::ReifyFnPointer => (
+                        "<fn-item-to-fn-pointer>",
+                        "fn item to fn pointer",
+                        "Converts a named function to a function pointer `fn()`. Useful when passing functions as values.",
+                    ),
                     PointerCast::UnsafeFnPointer => (
                         "<safe-fn-pointer-to-unsafe-fn-pointer>",
                         "safe fn pointer to unsafe fn pointer",
+                        "Coerces a safe function pointer to an unsafe one. Allows calling it in an unsafe context.",
+                    ),
+                    PointerCast::ClosureFnPointer(Safety::Unsafe) => (
+                        "<closure-to-unsafe-fn-pointer>",
+                        "closure to unsafe fn pointer",
+                        "Converts a non-capturing closure to an unsafe function pointer. Required for use in `extern` or unsafe APIs.",
+                    ),
+                    PointerCast::ClosureFnPointer(Safety::Safe) => (
+                        "<closure-to-fn-pointer>",
+                        "closure to fn pointer",
+                        "Converts a non-capturing closure to a function pointer. Lets closures behave like plain functions.",
+                    ),
+                    PointerCast::MutToConstPointer => (
+                        "<mut-ptr-to-const-ptr>",
+                        "mut ptr to const ptr",
+                        "Coerces `*mut T` to `*const T`. Safe because const pointers restrict what you can do.",
+                    ),
+                    PointerCast::ArrayToPointer => (
+                        "<array-ptr-to-element-ptr>",
+                        "array to pointer",
+                        "Converts an array to a pointer to its first element. Similar to how arrays decay to pointers in C.",
+                    ),
+                    PointerCast::Unsize => (
+                        "<unsize>",
+                        "unsize coercion",
+                        "Converts a sized type to an unsized one. Used for things like turning arrays into slices or concrete types into trait objects.",
                     ),
-                    PointerCast::ClosureFnPointer(Safety::Unsafe) => {
-                        ("<closure-to-unsafe-fn-pointer>", "closure to unsafe fn pointer")
-                    }
-                    PointerCast::ClosureFnPointer(Safety::Safe) => {
-                        ("<closure-to-fn-pointer>", "closure to fn pointer")
-                    }
-                    PointerCast::MutToConstPointer => {
-                        ("<mut-ptr-to-const-ptr>", "mut ptr to const ptr")
-                    }
-                    PointerCast::ArrayToPointer => ("<array-ptr-to-element-ptr>", ""),
-                    PointerCast::Unsize => ("<unsize>", "unsize"),
                 }
             }
             _ => continue,
@@ -162,9 +202,11 @@ pub(super) fn hints(
             linked_location: None,
             tooltip: Some(config.lazy_tooltip(|| {
                 InlayTooltip::Markdown(format!(
-                    "`{}` → `{}` ({coercion} coercion)",
+                    "`{}` → `{}`\n\n**{}**\n\n{}",
                     source.display(sema.db, display_target),
                     target.display(sema.db, display_target),
+                    coercion,
+                    detailed_tooltip
                 ))
             })),
         };
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 36fdd90e8ae..729349365e6 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
@@ -380,9 +380,9 @@ fn main() {
     let foo = foo3();
      // ^^^ impl Fn(f64, f64) -> u32
     let foo = foo4();
-     // ^^^ &'static (dyn Fn(f64, f64) -> u32 + 'static)
+     // ^^^ &'static dyn Fn(f64, f64) -> u32
     let foo = foo5();
-     // ^^^ &'static (dyn Fn(&(dyn Fn(f64, f64) -> u32 + 'static), f64) -> u32 + 'static)
+     // ^^^ &'static dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32
     let foo = foo6();
      // ^^^ impl Fn(f64, f64) -> u32
     let foo = foo7();
@@ -413,7 +413,7 @@ fn main() {
     let foo = foo3();
      // ^^^ impl Fn(f64, f64) -> u32
     let foo = foo4();
-     // ^^^ &'static (dyn Fn(f64, f64) -> u32 + 'static)
+     // ^^^ &'static dyn Fn(f64, f64) -> u32
     let foo = foo5();
     let foo = foo6();
     let foo = foo7();
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
index b9a98f88be7..f0003dae3f3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs
@@ -143,7 +143,7 @@ fn foo<T>() {}
                                             file_id: FileId(
                                                 1,
                                             ),
-                                            range: 135..140,
+                                            range: 446..451,
                                         },
                                     ),
                                 ),
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
index ca3a982760f..05253b67948 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
@@ -91,8 +91,6 @@ pub(super) fn hints(
         match_ast! {
             match parent {
                 ast::Fn(it) => {
-                    // FIXME: this could include parameters, but `HirDisplay` prints too much info
-                    // and doesn't respect the max length either, so the hints end up way too long
                     (format!("fn {}", it.name()?), it.name().map(name))
                 },
                 ast::Static(it) => (format!("static {}", it.name()?), it.name().map(name)),
@@ -193,7 +191,7 @@ impl Tr for () {
 //^ impl Tr for ()
 impl dyn Tr {
   }
-//^ impl dyn Tr + 'static
+//^ impl dyn Tr
 
 static S0: () = 0;
 static S1: () = {};
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 4c7c597e684..7dc18141bdb 100644
--- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
@@ -844,7 +844,7 @@ pub(crate) fn orig_range_with_focus_r(
                             // *should* contain the name
                             _ => {
                                 let kind = call_kind();
-                                let range = kind.clone().original_call_range_with_body(db);
+                                let range = kind.clone().original_call_range_with_input(db);
                                 //If the focus range is in the attribute/derive body, we
                                 // need to point the call site to the entire body, if not, fall back
                                 // to the name range of the attribute/derive call
diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs
index c6a323d4081..fe874bc99b4 100644
--- a/src/tools/rust-analyzer/crates/ide/src/references.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/references.rs
@@ -21,6 +21,7 @@ use hir::{PathResolution, Semantics};
 use ide_db::{
     FileId, RootDatabase,
     defs::{Definition, NameClass, NameRefClass},
+    helpers::pick_best_token,
     search::{ReferenceCategory, SearchScope, UsageSearchResult},
 };
 use itertools::Itertools;
@@ -397,7 +398,11 @@ fn handle_control_flow_keywords(
         .attach_first_edition(file_id)
         .map(|it| it.edition(sema.db))
         .unwrap_or(Edition::CURRENT);
-    let token = file.syntax().token_at_offset(offset).find(|t| t.kind().is_keyword(edition))?;
+    let token = pick_best_token(file.syntax().token_at_offset(offset), |kind| match kind {
+        _ if kind.is_keyword(edition) => 4,
+        T![=>] => 3,
+        _ => 1,
+    })?;
 
     let references = match token.kind() {
         T![fn] | T![return] | T![try] => highlight_related::highlight_exit_points(sema, token),
@@ -408,6 +413,7 @@ fn handle_control_flow_keywords(
         T![for] if token.parent().and_then(ast::ForExpr::cast).is_some() => {
             highlight_related::highlight_break_points(sema, token)
         }
+        T![if] | T![=>] | T![match] => highlight_related::highlight_branch_exit_points(sema, token),
         _ => return None,
     }
     .into_iter()
@@ -1344,6 +1350,159 @@ impl Foo {
         );
     }
 
+    #[test]
+    fn test_highlight_if_branches() {
+        check(
+            r#"
+fn main() {
+    let x = if$0 true {
+        1
+    } else if false {
+        2
+    } else {
+        3
+    };
+
+    println!("x: {}", x);
+}
+"#,
+            expect![[r#"
+                FileId(0) 24..26
+                FileId(0) 42..43
+                FileId(0) 55..57
+                FileId(0) 74..75
+                FileId(0) 97..98
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_highlight_match_branches() {
+        check(
+            r#"
+fn main() {
+    $0match Some(42) {
+        Some(x) if x > 0 => println!("positive"),
+        Some(0) => println!("zero"),
+        Some(_) => println!("negative"),
+        None => println!("none"),
+    };
+}
+"#,
+            expect![[r#"
+                FileId(0) 16..21
+                FileId(0) 61..81
+                FileId(0) 102..118
+                FileId(0) 139..159
+                FileId(0) 177..193
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_highlight_match_arm_arrow() {
+        check(
+            r#"
+fn main() {
+    match Some(42) {
+        Some(x) if x > 0 $0=> println!("positive"),
+        Some(0) => println!("zero"),
+        Some(_) => println!("negative"),
+        None => println!("none"),
+    }
+}
+"#,
+            expect![[r#"
+                FileId(0) 58..60
+                FileId(0) 61..81
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_highlight_nested_branches() {
+        check(
+            r#"
+fn main() {
+    let x = $0if true {
+        if false {
+            1
+        } else {
+            match Some(42) {
+                Some(_) => 2,
+                None => 3,
+            }
+        }
+    } else {
+        4
+    };
+
+    println!("x: {}", x);
+}
+"#,
+            expect![[r#"
+                FileId(0) 24..26
+                FileId(0) 65..66
+                FileId(0) 140..141
+                FileId(0) 167..168
+                FileId(0) 215..216
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_highlight_match_with_complex_guards() {
+        check(
+            r#"
+fn main() {
+    let x = $0match (x, y) {
+        (a, b) if a > b && a % 2 == 0 => 1,
+        (a, b) if a < b || b % 2 == 1 => 2,
+        (a, _) if a > 40 => 3,
+        _ => 4,
+    };
+
+    println!("x: {}", x);
+}
+"#,
+            expect![[r#"
+                FileId(0) 24..29
+                FileId(0) 80..81
+                FileId(0) 124..125
+                FileId(0) 155..156
+                FileId(0) 171..172
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_highlight_mixed_if_match_expressions() {
+        check(
+            r#"
+fn main() {
+    let x = $0if let Some(x) = Some(42) {
+        1
+    } else if let None = None {
+        2
+    } else {
+        match 42 {
+            0 => 3,
+            _ => 4,
+        }
+    };
+}
+"#,
+            expect![[r#"
+                FileId(0) 24..26
+                FileId(0) 60..61
+                FileId(0) 73..75
+                FileId(0) 102..103
+                FileId(0) 153..154
+                FileId(0) 173..174
+            "#]],
+        );
+    }
+
     fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
         check_with_scope(ra_fixture, None, expect)
     }
@@ -2867,4 +3026,66 @@ const FOO$0: i32 = 0;
             "#]],
         );
     }
+
+    #[test]
+    fn test_highlight_if_let_match_combined() {
+        check(
+            r#"
+enum MyEnum { A(i32), B(String), C }
+
+fn main() {
+    let val = MyEnum::A(42);
+
+    let x = $0if let MyEnum::A(x) = val {
+        1
+    } else if let MyEnum::B(s) = val {
+        2
+    } else {
+        match val {
+            MyEnum::C => 3,
+            _ => 4,
+        }
+    };
+}
+"#,
+            expect![[r#"
+                FileId(0) 92..94
+                FileId(0) 128..129
+                FileId(0) 141..143
+                FileId(0) 177..178
+                FileId(0) 237..238
+                FileId(0) 257..258
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_highlight_nested_match_expressions() {
+        check(
+            r#"
+enum Outer { A(Inner), B }
+enum Inner { X, Y(i32) }
+
+fn main() {
+    let val = Outer::A(Inner::Y(42));
+
+    $0match val {
+        Outer::A(inner) => match inner {
+            Inner::X => println!("Inner::X"),
+            Inner::Y(n) if n > 0 => println!("Inner::Y positive: {}", n),
+            Inner::Y(_) => println!("Inner::Y non-positive"),
+        },
+        Outer::B => println!("Outer::B"),
+    }
+}
+"#,
+            expect![[r#"
+                FileId(0) 108..113
+                FileId(0) 185..205
+                FileId(0) 243..279
+                FileId(0) 308..341
+                FileId(0) 374..394
+            "#]],
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
index f48150b369f..9d1a5bae96f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
@@ -351,7 +351,7 @@ pub(crate) fn runnable_fn(
     )
     .call_site();
 
-    let file_range = fn_source.syntax().original_file_range_with_macro_call_body(sema.db);
+    let file_range = fn_source.syntax().original_file_range_with_macro_call_input(sema.db);
     let update_test =
         UpdateTest::find_snapshot_macro(sema, &fn_source.file_syntax(sema.db), file_range);
 
@@ -425,7 +425,7 @@ pub(crate) fn runnable_impl(
 
     let impl_source = sema.source(*def)?;
     let impl_syntax = impl_source.syntax();
-    let file_range = impl_syntax.original_file_range_with_macro_call_body(sema.db);
+    let file_range = impl_syntax.original_file_range_with_macro_call_input(sema.db);
     let update_test =
         UpdateTest::find_snapshot_macro(sema, &impl_syntax.file_syntax(sema.db), file_range);
 
@@ -1241,10 +1241,10 @@ generate_main!();
                 [
                     "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..345, name: \"\", kind: Module })",
                     "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 282..312, focus_range: 286..291, name: \"tests\", kind: Module, description: \"mod tests\" })",
-                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 298..310, name: \"foo_test\", kind: Function })",
-                    "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 313..326, name: \"tests2\", kind: Module, description: \"mod tests2\" }, true)",
-                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 313..326, name: \"foo_test2\", kind: Function }, true)",
-                    "(Bin, NavigationTarget { file_id: FileId(0), full_range: 327..344, name: \"main\", kind: Function })",
+                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 298..307, name: \"foo_test\", kind: Function })",
+                    "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 313..323, name: \"tests2\", kind: Module, description: \"mod tests2\" }, true)",
+                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 313..323, name: \"foo_test2\", kind: Function }, true)",
+                    "(Bin, NavigationTarget { file_id: FileId(0), full_range: 327..341, name: \"main\", kind: Function })",
                 ]
             "#]],
         );
@@ -1272,10 +1272,10 @@ foo!();
 "#,
             expect![[r#"
                 [
-                    "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 210..217, name: \"foo_tests\", kind: Module, description: \"mod foo_tests\" }, true)",
-                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 210..217, name: \"foo0\", kind: Function }, true)",
-                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 210..217, name: \"foo1\", kind: Function }, true)",
-                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 210..217, name: \"foo2\", kind: Function }, true)",
+                    "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 210..214, name: \"foo_tests\", kind: Module, description: \"mod foo_tests\" }, true)",
+                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 210..214, name: \"foo0\", kind: Function }, true)",
+                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 210..214, name: \"foo1\", kind: Function }, true)",
+                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 210..214, name: \"foo2\", kind: Function }, true)",
                 ]
             "#]],
         );
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs b/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs
index 7985279679c..25deffe10eb 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs
@@ -79,7 +79,7 @@ impl<'a> dot::Labeller<'a, Crate, Edge<'a>> for DotCrateGraph<'_> {
     }
 
     fn node_id(&'a self, n: &Crate) -> Id<'a> {
-        let id = n.as_id().as_u32();
+        let id = n.as_id().index();
         Id::new(format!("_{id:?}")).unwrap()
     }
 
diff --git a/src/tools/rust-analyzer/crates/intern/Cargo.toml b/src/tools/rust-analyzer/crates/intern/Cargo.toml
index 9ff656cb744..81b6703deef 100644
--- a/src/tools/rust-analyzer/crates/intern/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/intern/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 
 [dependencies]
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 adc581309d1..1ccd20c25e9 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
@@ -438,6 +438,8 @@ define_symbols! {
     shr,
     simd,
     sized,
+    meta_sized,
+    pointee_sized,
     skip,
     slice_len_fn,
     Some,
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 52f59679b58..26ee698af08 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -11,7 +11,7 @@ use hir_expand::proc_macro::{
 };
 use ide_db::{
     ChangeWithProcMacros, FxHashMap, RootDatabase,
-    base_db::{CrateGraphBuilder, Env, SourceRoot, SourceRootId},
+    base_db::{CrateGraphBuilder, Env, ProcMacroLoadingError, SourceRoot, SourceRootId},
     prime_caches,
 };
 use itertools::Itertools;
@@ -69,6 +69,23 @@ pub fn load_workspace(
     extra_env: &FxHashMap<String, Option<String>>,
     load_config: &LoadCargoConfig,
 ) -> anyhow::Result<(RootDatabase, vfs::Vfs, Option<ProcMacroClient>)> {
+    let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<u16>().ok());
+    let mut db = RootDatabase::new(lru_cap);
+
+    let (vfs, proc_macro_server) = load_workspace_into_db(ws, extra_env, load_config, &mut db)?;
+
+    Ok((db, vfs, proc_macro_server))
+}
+
+// This variant of `load_workspace` allows deferring the loading of rust-analyzer
+// into an existing database, which is useful in certain third-party scenarios,
+// now that `salsa` supports extending foreign databases (e.g. `RootDatabase`).
+pub fn load_workspace_into_db(
+    ws: ProjectWorkspace,
+    extra_env: &FxHashMap<String, Option<String>>,
+    load_config: &LoadCargoConfig,
+    db: &mut RootDatabase,
+) -> anyhow::Result<(vfs::Vfs, Option<ProcMacroClient>)> {
     let (sender, receiver) = unbounded();
     let mut vfs = vfs::Vfs::default();
     let mut loader = {
@@ -78,23 +95,27 @@ pub fn load_workspace(
 
     tracing::debug!(?load_config, "LoadCargoConfig");
     let proc_macro_server = match &load_config.with_proc_macro_server {
-        ProcMacroServerChoice::Sysroot => ws
-            .find_sysroot_proc_macro_srv()
-            .and_then(|it| ProcMacroClient::spawn(&it, extra_env).map_err(Into::into))
-            .map_err(|e| (e, true)),
+        ProcMacroServerChoice::Sysroot => ws.find_sysroot_proc_macro_srv().map(|it| {
+            it.and_then(|it| ProcMacroClient::spawn(&it, extra_env).map_err(Into::into)).map_err(
+                |e| ProcMacroLoadingError::ProcMacroSrvError(e.to_string().into_boxed_str()),
+            )
+        }),
         ProcMacroServerChoice::Explicit(path) => {
-            ProcMacroClient::spawn(path, extra_env).map_err(Into::into).map_err(|e| (e, true))
-        }
-        ProcMacroServerChoice::None => {
-            Err((anyhow::format_err!("proc macro server disabled"), false))
+            Some(ProcMacroClient::spawn(path, extra_env).map_err(|e| {
+                ProcMacroLoadingError::ProcMacroSrvError(e.to_string().into_boxed_str())
+            }))
         }
+        ProcMacroServerChoice::None => Some(Err(ProcMacroLoadingError::Disabled)),
     };
     match &proc_macro_server {
-        Ok(server) => {
-            tracing::info!(path=%server.server_path(), "Proc-macro server started")
+        Some(Ok(server)) => {
+            tracing::info!(manifest=%ws.manifest_or_root(), path=%server.server_path(), "Proc-macro server started")
         }
-        Err((e, _)) => {
-            tracing::info!(%e, "Failed to start proc-macro server")
+        Some(Err(e)) => {
+            tracing::info!(manifest=%ws.manifest_or_root(), %e, "Failed to start proc-macro server")
+        }
+        None => {
+            tracing::info!(manifest=%ws.manifest_or_root(), "No proc-macro server started")
         }
     }
 
@@ -111,22 +132,24 @@ pub fn load_workspace(
     );
     let proc_macros = {
         let proc_macro_server = match &proc_macro_server {
-            Ok(it) => Ok(it),
-            Err((e, hard_err)) => Err((e.to_string(), *hard_err)),
+            Some(Ok(it)) => Ok(it),
+            Some(Err(e)) => {
+                Err(ProcMacroLoadingError::ProcMacroSrvError(e.to_string().into_boxed_str()))
+            }
+            None => Err(ProcMacroLoadingError::ProcMacroSrvError(
+                "proc-macro-srv is not running, workspace is missing a sysroot".into(),
+            )),
         };
         proc_macros
             .into_iter()
             .map(|(crate_id, path)| {
                 (
                     crate_id,
-                    path.map_or_else(
-                        |e| Err((e, true)),
-                        |(_, path)| {
-                            proc_macro_server.as_ref().map_err(Clone::clone).and_then(
-                                |proc_macro_server| load_proc_macro(proc_macro_server, &path, &[]),
-                            )
-                        },
-                    ),
+                    path.map_or_else(Err, |(_, path)| {
+                        proc_macro_server.as_ref().map_err(Clone::clone).and_then(
+                            |proc_macro_server| load_proc_macro(proc_macro_server, &path, &[]),
+                        )
+                    }),
                 )
             })
             .collect()
@@ -139,18 +162,20 @@ pub fn load_workspace(
         version: 0,
     });
 
-    let db = load_crate_graph(
+    load_crate_graph_into_db(
         crate_graph,
         proc_macros,
         project_folders.source_root_config,
         &mut vfs,
         &receiver,
+        db,
     );
 
     if load_config.prefill_caches {
-        prime_caches::parallel_prime_caches(&db, 1, &|_| ());
+        prime_caches::parallel_prime_caches(db, 1, &|_| ());
     }
-    Ok((db, vfs, proc_macro_server.ok()))
+
+    Ok((vfs, proc_macro_server.and_then(Result::ok)))
 }
 
 #[derive(Default)]
@@ -391,11 +416,13 @@ pub fn load_proc_macro(
     path: &AbsPath,
     ignored_macros: &[Box<str>],
 ) -> ProcMacroLoadResult {
-    let res: Result<Vec<_>, String> = (|| {
+    let res: Result<Vec<_>, _> = (|| {
         let dylib = MacroDylib::new(path.to_path_buf());
-        let vec = server.load_dylib(dylib).map_err(|e| format!("{e}"))?;
+        let vec = server.load_dylib(dylib).map_err(|e| {
+            ProcMacroLoadingError::ProcMacroSrvError(format!("{e}").into_boxed_str())
+        })?;
         if vec.is_empty() {
-            return Err("proc macro library returned no proc macros".to_owned());
+            return Err(ProcMacroLoadingError::NoProcMacros);
         }
         Ok(vec
             .into_iter()
@@ -412,20 +439,19 @@ pub fn load_proc_macro(
         }
         Err(e) => {
             tracing::warn!("proc-macro loading for {path} failed: {e}");
-            Err((e, true))
+            Err(e)
         }
     }
 }
 
-fn load_crate_graph(
+fn load_crate_graph_into_db(
     crate_graph: CrateGraphBuilder,
     proc_macros: ProcMacrosBuilder,
     source_root_config: SourceRootConfig,
     vfs: &mut vfs::Vfs,
     receiver: &Receiver<vfs::loader::Message>,
-) -> RootDatabase {
-    let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<u16>().ok());
-    let mut db = RootDatabase::new(lru_cap);
+    db: &mut RootDatabase,
+) {
     let mut analysis_change = ChangeWithProcMacros::default();
 
     db.enable_proc_attr_macros();
@@ -462,7 +488,6 @@ fn load_crate_graph(
     analysis_change.set_proc_macros(proc_macros);
 
     db.apply_change(analysis_change);
-    db
 }
 
 fn expander_to_proc_macro(
diff --git a/src/tools/rust-analyzer/crates/mbe/Cargo.toml b/src/tools/rust-analyzer/crates/mbe/Cargo.toml
index f3ab093bae0..eef718b7062 100644
--- a/src/tools/rust-analyzer/crates/mbe/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/mbe/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 cov-mark = "2.0.0"
diff --git a/src/tools/rust-analyzer/crates/parser/Cargo.toml b/src/tools/rust-analyzer/crates/parser/Cargo.toml
index c80510eedfb..c7da654de6d 100644
--- a/src/tools/rust-analyzer/crates/parser/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/parser/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 drop_bomb = "0.1.5"
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
index ea5a3bc8593..55c5dc400b9 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
@@ -122,7 +122,7 @@ fn lifetime_bounds(p: &mut Parser<'_>) {
 }
 
 // test type_param_bounds
-// struct S<T: 'a + ?Sized + (Copy) + ~const Drop>;
+// struct S<T: 'a + ?Sized + (Copy) + [const] Drop>;
 pub(super) fn bounds(p: &mut Parser<'_>) {
     p.expect(T![:]);
     bounds_without_colon(p);
@@ -187,6 +187,11 @@ fn type_bound(p: &mut Parser<'_>) -> bool {
                     p.bump_any();
                     p.expect(T![const]);
                 }
+                T!['['] => {
+                    p.bump_any();
+                    p.expect(T![const]);
+                    p.expect(T![']']);
+                }
                 // test const_trait_bound
                 // const fn foo(_: impl const Trait) {}
                 T![const] => {
diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
index 0fa9a264545..e6c92dec681 100644
--- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
@@ -11,7 +11,8 @@
 use std::ops;
 
 use rustc_literal_escaper::{
-    EscapeError, Mode, unescape_byte, unescape_char, unescape_mixed, unescape_unicode,
+    EscapeError, Mode, unescape_byte, unescape_byte_str, unescape_c_str, unescape_char,
+    unescape_str,
 };
 
 use crate::{
@@ -151,14 +152,14 @@ impl<'a> Converter<'a> {
         self.res
     }
 
-    fn push(&mut self, kind: SyntaxKind, len: usize, err: Option<&str>) {
+    fn push(&mut self, kind: SyntaxKind, len: usize, errors: Vec<String>) {
         self.res.push(kind, self.offset);
         self.offset += len;
 
-        if let Some(err) = err {
-            let token = self.res.len() as u32;
-            let msg = err.to_owned();
-            self.res.error.push(LexError { msg, token });
+        for msg in errors {
+            if !msg.is_empty() {
+                self.res.error.push(LexError { msg, token: self.res.len() as u32 });
+            }
         }
     }
 
@@ -167,14 +168,16 @@ impl<'a> Converter<'a> {
         // We drop some useful information here (see patterns with double dots `..`)
         // Storing that info in `SyntaxKind` is not possible due to its layout requirements of
         // being `u16` that come from `rowan::SyntaxKind`.
-        let mut err = "";
+        let mut errors: Vec<String> = vec![];
 
         let syntax_kind = {
             match kind {
                 rustc_lexer::TokenKind::LineComment { doc_style: _ } => COMMENT,
                 rustc_lexer::TokenKind::BlockComment { doc_style: _, terminated } => {
                     if !terminated {
-                        err = "Missing trailing `*/` symbols to terminate the block comment";
+                        errors.push(
+                            "Missing trailing `*/` symbols to terminate the block comment".into(),
+                        );
                     }
                     COMMENT
                 }
@@ -184,9 +187,9 @@ impl<'a> Converter<'a> {
                     invalid_infostring,
                 } => {
                     if *has_invalid_preceding_whitespace {
-                        err = "invalid preceding whitespace for frontmatter opening"
+                        errors.push("invalid preceding whitespace for frontmatter opening".into());
                     } else if *invalid_infostring {
-                        err = "invalid infostring for frontmatter"
+                        errors.push("invalid infostring for frontmatter".into());
                     }
                     FRONTMATTER
                 }
@@ -198,7 +201,7 @@ impl<'a> Converter<'a> {
                     SyntaxKind::from_keyword(token_text, self.edition).unwrap_or(IDENT)
                 }
                 rustc_lexer::TokenKind::InvalidIdent => {
-                    err = "Ident contains invalid characters";
+                    errors.push("Ident contains invalid characters".into());
                     IDENT
                 }
 
@@ -206,7 +209,7 @@ impl<'a> Converter<'a> {
 
                 rustc_lexer::TokenKind::GuardedStrPrefix if self.edition.at_least_2024() => {
                     // FIXME: rustc does something better for recovery.
-                    err = "Invalid string literal (reserved syntax)";
+                    errors.push("Invalid string literal (reserved syntax)".into());
                     ERROR
                 }
                 rustc_lexer::TokenKind::GuardedStrPrefix => {
@@ -222,12 +225,12 @@ impl<'a> Converter<'a> {
 
                 rustc_lexer::TokenKind::Lifetime { starts_with_number } => {
                     if *starts_with_number {
-                        err = "Lifetime name cannot start with a number";
+                        errors.push("Lifetime name cannot start with a number".into());
                     }
                     LIFETIME_IDENT
                 }
                 rustc_lexer::TokenKind::UnknownPrefixLifetime => {
-                    err = "Unknown lifetime prefix";
+                    errors.push("Unknown lifetime prefix".into());
                     LIFETIME_IDENT
                 }
                 rustc_lexer::TokenKind::RawLifetime => LIFETIME_IDENT,
@@ -262,119 +265,128 @@ impl<'a> Converter<'a> {
                 rustc_lexer::TokenKind::Unknown => ERROR,
                 rustc_lexer::TokenKind::UnknownPrefix if token_text == "builtin" => IDENT,
                 rustc_lexer::TokenKind::UnknownPrefix => {
-                    err = "unknown literal prefix";
+                    errors.push("unknown literal prefix".into());
                     IDENT
                 }
                 rustc_lexer::TokenKind::Eof => EOF,
             }
         };
 
-        let err = if err.is_empty() { None } else { Some(err) };
-        self.push(syntax_kind, token_text.len(), err);
+        self.push(syntax_kind, token_text.len(), errors);
     }
 
     fn extend_literal(&mut self, len: usize, kind: &rustc_lexer::LiteralKind) {
-        let mut err = "";
+        let invalid_raw_msg = String::from("Invalid raw string literal");
+
+        let mut errors = vec![];
+        let mut no_end_quote = |c: char, kind: &str| {
+            errors.push(format!("Missing trailing `{c}` symbol to terminate the {kind} literal"));
+        };
 
         let syntax_kind = match *kind {
             rustc_lexer::LiteralKind::Int { empty_int, base: _ } => {
                 if empty_int {
-                    err = "Missing digits after the integer base prefix";
+                    errors.push("Missing digits after the integer base prefix".into());
                 }
                 INT_NUMBER
             }
             rustc_lexer::LiteralKind::Float { empty_exponent, base: _ } => {
                 if empty_exponent {
-                    err = "Missing digits after the exponent symbol";
+                    errors.push("Missing digits after the exponent symbol".into());
                 }
                 FLOAT_NUMBER
             }
             rustc_lexer::LiteralKind::Char { terminated } => {
                 if !terminated {
-                    err = "Missing trailing `'` symbol to terminate the character literal";
+                    no_end_quote('\'', "character");
                 } else {
                     let text = &self.res.text[self.offset + 1..][..len - 1];
-                    let i = text.rfind('\'').unwrap();
-                    let text = &text[..i];
+                    let text = &text[..text.rfind('\'').unwrap()];
                     if let Err(e) = unescape_char(text) {
-                        err = error_to_diagnostic_message(e, Mode::Char);
+                        errors.push(err_to_msg(e, Mode::Char));
                     }
                 }
                 CHAR
             }
             rustc_lexer::LiteralKind::Byte { terminated } => {
                 if !terminated {
-                    err = "Missing trailing `'` symbol to terminate the byte literal";
+                    no_end_quote('\'', "byte");
                 } else {
                     let text = &self.res.text[self.offset + 2..][..len - 2];
-                    let i = text.rfind('\'').unwrap();
-                    let text = &text[..i];
+                    let text = &text[..text.rfind('\'').unwrap()];
                     if let Err(e) = unescape_byte(text) {
-                        err = error_to_diagnostic_message(e, Mode::Byte);
+                        errors.push(err_to_msg(e, Mode::Byte));
                     }
                 }
-
                 BYTE
             }
             rustc_lexer::LiteralKind::Str { terminated } => {
                 if !terminated {
-                    err = "Missing trailing `\"` symbol to terminate the string literal";
+                    no_end_quote('"', "string");
                 } else {
                     let text = &self.res.text[self.offset + 1..][..len - 1];
-                    let i = text.rfind('"').unwrap();
-                    let text = &text[..i];
-                    err = unescape_string_error_message(text, Mode::Str);
+                    let text = &text[..text.rfind('"').unwrap()];
+                    unescape_str(text, |_, res| {
+                        if let Err(e) = res {
+                            errors.push(err_to_msg(e, Mode::Str));
+                        }
+                    });
                 }
                 STRING
             }
             rustc_lexer::LiteralKind::ByteStr { terminated } => {
                 if !terminated {
-                    err = "Missing trailing `\"` symbol to terminate the byte string literal";
+                    no_end_quote('"', "byte string");
                 } else {
                     let text = &self.res.text[self.offset + 2..][..len - 2];
-                    let i = text.rfind('"').unwrap();
-                    let text = &text[..i];
-                    err = unescape_string_error_message(text, Mode::ByteStr);
+                    let text = &text[..text.rfind('"').unwrap()];
+                    unescape_byte_str(text, |_, res| {
+                        if let Err(e) = res {
+                            errors.push(err_to_msg(e, Mode::ByteStr));
+                        }
+                    });
                 }
                 BYTE_STRING
             }
             rustc_lexer::LiteralKind::CStr { terminated } => {
                 if !terminated {
-                    err = "Missing trailing `\"` symbol to terminate the string literal";
+                    no_end_quote('"', "C string")
                 } else {
                     let text = &self.res.text[self.offset + 2..][..len - 2];
-                    let i = text.rfind('"').unwrap();
-                    let text = &text[..i];
-                    err = unescape_string_error_message(text, Mode::CStr);
+                    let text = &text[..text.rfind('"').unwrap()];
+                    unescape_c_str(text, |_, res| {
+                        if let Err(e) = res {
+                            errors.push(err_to_msg(e, Mode::CStr));
+                        }
+                    });
                 }
                 C_STRING
             }
             rustc_lexer::LiteralKind::RawStr { n_hashes } => {
                 if n_hashes.is_none() {
-                    err = "Invalid raw string literal";
+                    errors.push(invalid_raw_msg);
                 }
                 STRING
             }
             rustc_lexer::LiteralKind::RawByteStr { n_hashes } => {
                 if n_hashes.is_none() {
-                    err = "Invalid raw string literal";
+                    errors.push(invalid_raw_msg);
                 }
                 BYTE_STRING
             }
             rustc_lexer::LiteralKind::RawCStr { n_hashes } => {
                 if n_hashes.is_none() {
-                    err = "Invalid raw string literal";
+                    errors.push(invalid_raw_msg);
                 }
                 C_STRING
             }
         };
 
-        let err = if err.is_empty() { None } else { Some(err) };
-        self.push(syntax_kind, len, err);
+        self.push(syntax_kind, len, errors);
     }
 }
 
-fn error_to_diagnostic_message(error: EscapeError, mode: Mode) -> &'static str {
+fn err_to_msg(error: EscapeError, mode: Mode) -> String {
     match error {
         EscapeError::ZeroChars => "empty character literal",
         EscapeError::MoreThanOneChar => "character literal may only contain one codepoint",
@@ -410,28 +422,5 @@ fn error_to_diagnostic_message(error: EscapeError, mode: Mode) -> &'static str {
         EscapeError::UnskippedWhitespaceWarning => "",
         EscapeError::MultipleSkippedLinesWarning => "",
     }
-}
-
-fn unescape_string_error_message(text: &str, mode: Mode) -> &'static str {
-    let mut error_message = "";
-    match mode {
-        Mode::CStr => {
-            unescape_mixed(text, mode, &mut |_, res| {
-                if let Err(e) = res {
-                    error_message = error_to_diagnostic_message(e, mode);
-                }
-            });
-        }
-        Mode::ByteStr | Mode::Str => {
-            unescape_unicode(text, mode, &mut |_, res| {
-                if let Err(e) = res {
-                    error_message = error_to_diagnostic_message(e, mode);
-                }
-            });
-        }
-        _ => {
-            // Other Modes are not supported yet or do not apply
-        }
-    }
-    error_message
+    .into()
 }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_param_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_param_bounds.rast
index dee860c2418..259637c898a 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_param_bounds.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_param_bounds.rast
@@ -40,8 +40,9 @@ SOURCE_FILE
           PLUS "+"
           WHITESPACE " "
           TYPE_BOUND
-            TILDE "~"
+            L_BRACK "["
             CONST_KW "const"
+            R_BRACK "]"
             WHITESPACE " "
             PATH_TYPE
               PATH
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_param_bounds.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_param_bounds.rs
index 5da3083b9c5..8f37af78e9f 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_param_bounds.rs
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_param_bounds.rs
@@ -1 +1 @@
-struct S<T: 'a + ?Sized + (Copy) + ~const Drop>;
+struct S<T: 'a + ?Sized + (Copy) + [const] Drop>;
diff --git a/src/tools/rust-analyzer/crates/paths/Cargo.toml b/src/tools/rust-analyzer/crates/paths/Cargo.toml
index 4cc70726da0..f0dafab70c1 100644
--- a/src/tools/rust-analyzer/crates/paths/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/paths/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 camino.workspace = true
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml
index f5ba40a994b..dac8e094357 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 serde.workspace = true
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 8fd675d0d31..4034f244393 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 object.workspace = true
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/Cargo.toml
index c416d997a89..bc04482273e 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2024"
 license = "MIT OR Apache-2.0"
 
 [lib]
+doctest = false
 
 [build-dependencies]
 cargo_metadata = "0.20.0"
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/build.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/build.rs
index b97569d4dbd..b9e84a474dd 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/build.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/build.rs
@@ -109,13 +109,11 @@ fn main() {
 
     let mut artifact_path = None;
     for message in Message::parse_stream(output.stdout.as_slice()) {
-        if let Message::CompilerArtifact(artifact) = message.unwrap() {
-            if artifact.target.kind.contains(&cargo_metadata::TargetKind::ProcMacro)
-                && (artifact.package_id.repr.starts_with(&repr)
-                    || artifact.package_id.repr == pkgid)
-            {
-                artifact_path = Some(PathBuf::from(&artifact.filenames[0]));
-            }
+        if let Message::CompilerArtifact(artifact) = message.unwrap()
+            && artifact.target.kind.contains(&cargo_metadata::TargetKind::ProcMacro)
+            && (artifact.package_id.repr.starts_with(&repr) || artifact.package_id.repr == pkgid)
+        {
+            artifact_path = Some(PathBuf::from(&artifact.filenames[0]));
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/Cargo.toml
index 33b7c2bb0ad..e1678bddff8 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/Cargo.toml
@@ -6,6 +6,7 @@ edition = "2024"
 publish = false
 
 [lib]
+doctest = false
 proc-macro = true
 
 [dependencies]
diff --git a/src/tools/rust-analyzer/crates/profile/Cargo.toml b/src/tools/rust-analyzer/crates/profile/Cargo.toml
index bae891c1984..4828419003a 100644
--- a/src/tools/rust-analyzer/crates/profile/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/profile/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 cfg-if = "1.0.1"
diff --git a/src/tools/rust-analyzer/crates/project-model/Cargo.toml b/src/tools/rust-analyzer/crates/project-model/Cargo.toml
index 64ea75922fb..27fe9f79bbc 100644
--- a/src/tools/rust-analyzer/crates/project-model/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/project-model/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 anyhow.workspace = true
diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
index 4435376eab6..499caa622c4 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
@@ -20,9 +20,7 @@ use toolchain::Tool;
 
 use crate::{
     CargoConfig, CargoFeatures, CargoWorkspace, InvocationStrategy, ManifestPath, Package, Sysroot,
-    TargetKind,
-    toolchain_info::{QueryConfig, version},
-    utf8_stdout,
+    TargetKind, utf8_stdout,
 };
 
 /// Output of the build script and proc-macro building steps for a workspace.
@@ -64,6 +62,7 @@ impl WorkspaceBuildScripts {
         workspace: &CargoWorkspace,
         progress: &dyn Fn(String),
         sysroot: &Sysroot,
+        toolchain: Option<&semver::Version>,
     ) -> io::Result<WorkspaceBuildScripts> {
         let current_dir = workspace.workspace_root();
 
@@ -74,6 +73,7 @@ impl WorkspaceBuildScripts {
             workspace.manifest_path(),
             current_dir,
             sysroot,
+            toolchain,
         )?;
         Self::run_per_ws(cmd, workspace, progress)
     }
@@ -95,6 +95,7 @@ impl WorkspaceBuildScripts {
             &ManifestPath::try_from(working_directory.clone()).unwrap(),
             working_directory,
             &Sysroot::empty(),
+            None,
         )?;
         // NB: Cargo.toml could have been modified between `cargo metadata` and
         // `cargo check`. We shouldn't assume that package ids we see here are
@@ -311,7 +312,9 @@ impl WorkspaceBuildScripts {
                 match message {
                     Message::BuildScriptExecuted(mut message) => {
                         with_output_for(&message.package_id.repr, &mut |name, data| {
-                            progress(format!("running build-script: {name}"));
+                            progress(format!(
+                                "building compile-time-deps: build script {name} run"
+                            ));
                             let cfgs = {
                                 let mut acc = Vec::new();
                                 for cfg in &message.cfgs {
@@ -342,7 +345,9 @@ impl WorkspaceBuildScripts {
                     }
                     Message::CompilerArtifact(message) => {
                         with_output_for(&message.package_id.repr, &mut |name, data| {
-                            progress(format!("building proc-macros: {name}"));
+                            progress(format!(
+                                "building compile-time-deps: proc-macro {name} built"
+                            ));
                             if message.target.kind.contains(&cargo_metadata::TargetKind::ProcMacro)
                             {
                                 // Skip rmeta file
@@ -356,7 +361,7 @@ impl WorkspaceBuildScripts {
                         });
                     }
                     Message::CompilerMessage(message) => {
-                        progress(message.target.name);
+                        progress(format!("received compiler message for: {}", message.target.name));
 
                         if let Some(diag) = message.message.rendered.as_deref() {
                             push_err(diag);
@@ -387,12 +392,13 @@ impl WorkspaceBuildScripts {
         manifest_path: &ManifestPath,
         current_dir: &AbsPath,
         sysroot: &Sysroot,
+        toolchain: Option<&semver::Version>,
     ) -> io::Result<Command> {
-        let mut cmd = match config.run_build_script_command.as_deref() {
+        match config.run_build_script_command.as_deref() {
             Some([program, args @ ..]) => {
                 let mut cmd = toolchain::command(program, current_dir, &config.extra_env);
                 cmd.args(args);
-                cmd
+                Ok(cmd)
             }
             _ => {
                 let mut cmd = sysroot.tool(Tool::Cargo, current_dir, &config.extra_env);
@@ -407,13 +413,6 @@ impl WorkspaceBuildScripts {
                     cmd.arg("--target-dir").arg(target_dir);
                 }
 
-                // --all-targets includes tests, benches and examples in addition to the
-                // default lib and bins. This is an independent concept from the --target
-                // flag below.
-                if config.all_targets {
-                    cmd.arg("--all-targets");
-                }
-
                 if let Some(target) = &config.target {
                     cmd.args(["--target", target]);
                 }
@@ -444,40 +443,47 @@ impl WorkspaceBuildScripts {
 
                 cmd.arg("--keep-going");
 
-                cmd
-            }
-        };
-
-        // If [`--compile-time-deps` flag](https://github.com/rust-lang/cargo/issues/14434) is
-        // available in current toolchain's cargo, use it to build compile time deps only.
-        const COMP_TIME_DEPS_MIN_TOOLCHAIN_VERSION: semver::Version = semver::Version {
-            major: 1,
-            minor: 90,
-            patch: 0,
-            pre: semver::Prerelease::EMPTY,
-            build: semver::BuildMetadata::EMPTY,
-        };
+                // If [`--compile-time-deps` flag](https://github.com/rust-lang/cargo/issues/14434) is
+                // available in current toolchain's cargo, use it to build compile time deps only.
+                const COMP_TIME_DEPS_MIN_TOOLCHAIN_VERSION: semver::Version = semver::Version {
+                    major: 1,
+                    minor: 89,
+                    patch: 0,
+                    pre: semver::Prerelease::EMPTY,
+                    build: semver::BuildMetadata::EMPTY,
+                };
+
+                let cargo_comp_time_deps_available =
+                    toolchain.is_some_and(|v| *v >= COMP_TIME_DEPS_MIN_TOOLCHAIN_VERSION);
+
+                if cargo_comp_time_deps_available {
+                    cmd.env("__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS", "nightly");
+                    cmd.arg("-Zunstable-options");
+                    cmd.arg("--compile-time-deps");
+                    // we can pass this unconditionally, because we won't actually build the
+                    // binaries, and as such, this will succeed even on targets without libtest
+                    cmd.arg("--all-targets");
+                } else {
+                    // --all-targets includes tests, benches and examples in addition to the
+                    // default lib and bins. This is an independent concept from the --target
+                    // flag below.
+                    if config.all_targets {
+                        cmd.arg("--all-targets");
+                    }
 
-        let query_config = QueryConfig::Cargo(sysroot, manifest_path);
-        let toolchain = version::get(query_config, &config.extra_env).ok().flatten();
-        let cargo_comp_time_deps_available =
-            toolchain.is_some_and(|v| v >= COMP_TIME_DEPS_MIN_TOOLCHAIN_VERSION);
-
-        if cargo_comp_time_deps_available {
-            cmd.env("__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS", "nightly");
-            cmd.arg("-Zunstable-options");
-            cmd.arg("--compile-time-deps");
-        } else if config.wrap_rustc_in_build_scripts {
-            // Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use
-            // that to compile only proc macros and build scripts during the initial
-            // `cargo check`.
-            // We don't need this if we are using `--compile-time-deps` flag.
-            let myself = std::env::current_exe()?;
-            cmd.env("RUSTC_WRAPPER", myself);
-            cmd.env("RA_RUSTC_WRAPPER", "1");
+                    if config.wrap_rustc_in_build_scripts {
+                        // Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use
+                        // that to compile only proc macros and build scripts during the initial
+                        // `cargo check`.
+                        // We don't need this if we are using `--compile-time-deps` flag.
+                        let myself = std::env::current_exe()?;
+                        cmd.env("RUSTC_WRAPPER", myself);
+                        cmd.env("RA_RUSTC_WRAPPER", "1");
+                    }
+                }
+                Ok(cmd)
+            }
         }
-
-        Ok(cmd)
     }
 }
 
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 58507418e4d..4bacc904174 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
@@ -48,6 +48,7 @@ pub struct CargoWorkspace {
     is_sysroot: bool,
     /// Environment variables set in the `.cargo/config` file.
     config_env: Env,
+    requires_rustc_private: bool,
 }
 
 impl ops::Index<Package> for CargoWorkspace {
@@ -513,6 +514,7 @@ impl CargoWorkspace {
         let workspace_root = AbsPathBuf::assert(meta.workspace_root);
         let target_directory = AbsPathBuf::assert(meta.target_directory);
         let mut is_virtual_workspace = true;
+        let mut requires_rustc_private = false;
 
         meta.packages.sort_by(|a, b| a.id.cmp(&b.id));
         for meta_pkg in meta.packages {
@@ -577,6 +579,7 @@ impl CargoWorkspace {
                 metadata: meta.rust_analyzer.unwrap_or_default(),
             });
             let pkg_data = &mut packages[pkg];
+            requires_rustc_private |= pkg_data.metadata.rustc_private;
             pkg_by_id.insert(id, pkg);
             for meta_tgt in meta_targets {
                 let cargo_metadata::Target { name, kind, required_features, src_path, .. } =
@@ -626,6 +629,7 @@ impl CargoWorkspace {
             target_directory,
             manifest_path: ws_manifest_path,
             is_virtual_workspace,
+            requires_rustc_private,
             is_sysroot,
             config_env: cargo_config_env,
         }
@@ -724,4 +728,8 @@ impl CargoWorkspace {
     pub fn is_sysroot(&self) -> bool {
         self.is_sysroot
     }
+
+    pub fn requires_rustc_private(&self) -> bool {
+        self.requires_rustc_private
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/env.rs b/src/tools/rust-analyzer/crates/project-model/src/env.rs
index 450def5461d..9e0415c3b39 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/env.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/env.rs
@@ -1,6 +1,6 @@
 //! Cargo-like environment variables injection.
 use base_db::Env;
-use paths::Utf8Path;
+use paths::{Utf8Path, Utf8PathBuf};
 use rustc_hash::FxHashMap;
 use toolchain::Tool;
 
@@ -123,6 +123,26 @@ fn parse_output_cargo_config_env(manifest: &ManifestPath, stdout: &str) -> Env {
     env
 }
 
+pub(crate) fn cargo_config_build_target_dir(
+    manifest: &ManifestPath,
+    extra_env: &FxHashMap<String, Option<String>>,
+    sysroot: &Sysroot,
+) -> Option<Utf8PathBuf> {
+    let mut cargo_config = sysroot.tool(Tool::Cargo, manifest.parent(), extra_env);
+    cargo_config
+        .args(["-Z", "unstable-options", "config", "get", "build.target-dir"])
+        .env("RUSTC_BOOTSTRAP", "1");
+    if manifest.is_rust_manifest() {
+        cargo_config.arg("-Zscript");
+    }
+    utf8_stdout(&mut cargo_config)
+        .map(|stdout| {
+            Utf8Path::new(stdout.trim_start_matches("build.target-dir = ").trim_matches('"'))
+                .to_owned()
+        })
+        .ok()
+}
+
 #[test]
 fn parse_output_cargo_config_env_works() {
     let stdout = r#"
diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
index 4b34fc00711..9f19260d309 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
@@ -163,18 +163,18 @@ impl Sysroot {
         }
     }
 
-    pub fn discover_proc_macro_srv(&self) -> anyhow::Result<AbsPathBuf> {
-        let Some(root) = self.root() else {
-            return Err(anyhow::format_err!("no sysroot",));
-        };
-        ["libexec", "lib"]
-            .into_iter()
-            .map(|segment| root.join(segment).join("rust-analyzer-proc-macro-srv"))
-            .find_map(|server_path| probe_for_binary(server_path.into()))
-            .map(AbsPathBuf::assert)
-            .ok_or_else(|| {
-                anyhow::format_err!("cannot find proc-macro server in sysroot `{}`", root)
-            })
+    pub fn discover_proc_macro_srv(&self) -> Option<anyhow::Result<AbsPathBuf>> {
+        let root = self.root()?;
+        Some(
+            ["libexec", "lib"]
+                .into_iter()
+                .map(|segment| root.join(segment).join("rust-analyzer-proc-macro-srv"))
+                .find_map(|server_path| probe_for_binary(server_path.into()))
+                .map(AbsPathBuf::assert)
+                .ok_or_else(|| {
+                    anyhow::format_err!("cannot find proc-macro server in sysroot `{}`", root)
+                }),
+        )
     }
 
     fn assemble(
@@ -209,6 +209,7 @@ impl Sysroot {
     pub fn load_workspace(
         &self,
         sysroot_source_config: &RustSourceWorkspaceConfig,
+        no_deps: bool,
         current_dir: &AbsPath,
         progress: &dyn Fn(String),
     ) -> Option<RustLibSrcWorkspace> {
@@ -224,6 +225,7 @@ impl Sysroot {
                     &library_manifest,
                     current_dir,
                     cargo_config,
+                    no_deps,
                     progress,
                 ) {
                     Ok(loaded) => return Some(loaded),
@@ -318,6 +320,7 @@ impl Sysroot {
         library_manifest: &ManifestPath,
         current_dir: &AbsPath,
         cargo_config: &CargoMetadataConfig,
+        no_deps: bool,
         progress: &dyn Fn(String),
     ) -> Result<RustLibSrcWorkspace> {
         tracing::debug!("Loading library metadata: {library_manifest}");
@@ -333,7 +336,7 @@ impl Sysroot {
             current_dir,
             &cargo_config,
             self,
-            false,
+            no_deps,
             // Make sure we never attempt to write to the sysroot
             true,
             progress,
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 4f11af2d06c..f229e9a650d 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
@@ -240,7 +240,7 @@ fn smoke_test_real_sysroot_cargo() {
     let cwd = AbsPathBuf::assert_utf8(temp_dir().join("smoke_test_real_sysroot_cargo"));
     std::fs::create_dir_all(&cwd).unwrap();
     let loaded_sysroot =
-        sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo(), &cwd, &|_| ());
+        sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo(), false, &cwd, &|_| ());
     if let Some(loaded_sysroot) = loaded_sysroot {
         sysroot.set_workspace(loaded_sysroot);
     }
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 a6743a32b14..43db84b4fa3 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -7,8 +7,8 @@ use std::{collections::VecDeque, fmt, fs, iter, ops::Deref, sync, thread};
 use anyhow::Context;
 use base_db::{
     CrateBuilderId, CrateDisplayName, CrateGraphBuilder, CrateName, CrateOrigin,
-    CrateWorkspaceData, DependencyBuilder, Env, LangCrateOrigin, ProcMacroPaths,
-    TargetLayoutLoadResult,
+    CrateWorkspaceData, DependencyBuilder, Env, LangCrateOrigin, ProcMacroLoadingError,
+    ProcMacroPaths, TargetLayoutLoadResult,
 };
 use cfg::{CfgAtom, CfgDiff, CfgOptions};
 use intern::{Symbol, sym};
@@ -16,6 +16,7 @@ use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
 use rustc_hash::{FxHashMap, FxHashSet};
 use semver::Version;
 use span::{Edition, FileId};
+use toolchain::Tool;
 use tracing::instrument;
 use triomphe::Arc;
 
@@ -25,10 +26,14 @@ use crate::{
     WorkspaceBuildScripts,
     build_dependencies::BuildScriptOutput,
     cargo_workspace::{CargoMetadataConfig, DepKind, PackageData, RustLibSource},
-    env::{cargo_config_env, inject_cargo_env, inject_cargo_package_env, inject_rustc_tool_env},
+    env::{
+        cargo_config_build_target_dir, cargo_config_env, inject_cargo_env,
+        inject_cargo_package_env, inject_rustc_tool_env,
+    },
     project_json::{Crate, CrateArrayIdx},
     sysroot::RustLibSrcWorkspace,
     toolchain_info::{QueryConfig, rustc_cfg, target_data_layout, target_tuple, version},
+    utf8_stdout,
 };
 use tracing::{debug, error, info};
 
@@ -208,8 +213,7 @@ impl ProjectWorkspace {
         config: &CargoConfig,
         progress: &(dyn Fn(String) + Sync),
     ) -> Result<ProjectWorkspace, anyhow::Error> {
-        progress("Discovering sysroot".to_owned());
-        let workspace_dir = cargo_toml.parent();
+        progress("discovering sysroot".to_owned());
         let CargoConfig {
             features,
             rustc_source,
@@ -224,6 +228,7 @@ impl ProjectWorkspace {
             no_deps,
             ..
         } = config;
+        let workspace_dir = cargo_toml.parent();
         let mut sysroot = match (sysroot, sysroot_src) {
             (Some(RustLibSource::Discover), None) => Sysroot::discover(workspace_dir, extra_env),
             (Some(RustLibSource::Discover), Some(sysroot_src)) => {
@@ -238,8 +243,33 @@ impl ProjectWorkspace {
             (None, _) => Sysroot::empty(),
         };
 
+        // Resolve the Cargo.toml to the workspace root as we base the `target` dir off of it.
+        let mut cmd = sysroot.tool(Tool::Cargo, workspace_dir, extra_env);
+        cmd.args(["locate-project", "--workspace", "--manifest-path", cargo_toml.as_str()]);
+        let cargo_toml = &match utf8_stdout(&mut cmd) {
+            Ok(output) => {
+                #[derive(serde_derive::Deserialize)]
+                struct Root {
+                    root: Utf8PathBuf,
+                }
+                match serde_json::from_str::<Root>(&output) {
+                    Ok(object) => ManifestPath::try_from(AbsPathBuf::assert(object.root))
+                        .expect("manifest path should be absolute"),
+                    Err(e) => {
+                        tracing::error!(%e, %cargo_toml, "failed fetching cargo workspace root");
+                        cargo_toml.clone()
+                    }
+                }
+            }
+            Err(e) => {
+                tracing::error!(%e, %cargo_toml, "failed fetching cargo workspace root");
+                cargo_toml.clone()
+            }
+        };
+        let workspace_dir = cargo_toml.parent();
+
         tracing::info!(workspace = %cargo_toml, src_root = ?sysroot.rust_lib_src_root(), root = ?sysroot.root(), "Using sysroot");
-        progress("Querying project metadata".to_owned());
+        progress("querying project metadata".to_owned());
         let toolchain_config = QueryConfig::Cargo(&sysroot, cargo_toml);
         let targets =
             target_tuple::get(toolchain_config, target.as_deref(), extra_env).unwrap_or_default();
@@ -252,8 +282,11 @@ impl ProjectWorkspace {
             .ok()
             .flatten();
 
-        let target_dir =
-            config.target_dir.clone().unwrap_or_else(|| workspace_dir.join("target").into());
+        let target_dir = config
+            .target_dir
+            .clone()
+            .or_else(|| cargo_config_build_target_dir(cargo_toml, extra_env, &sysroot))
+            .unwrap_or_else(|| workspace_dir.join("target").into());
 
         // We spawn a bunch of processes to query various information about the workspace's
         // toolchain and sysroot
@@ -358,6 +391,7 @@ impl ProjectWorkspace {
                         toolchain.clone(),
                         target_dir.clone(),
                     )),
+                    config.no_deps,
                     workspace_dir,
                     progress,
                 )
@@ -374,11 +408,17 @@ impl ProjectWorkspace {
             ))
         });
 
-        let (rustc_cfg, data_layout, rustc, loaded_sysroot, cargo_metadata, cargo_config_extra_env) =
-            match join {
-                Ok(it) => it,
-                Err(e) => std::panic::resume_unwind(e),
-            };
+        let (
+            rustc_cfg,
+            data_layout,
+            mut rustc,
+            loaded_sysroot,
+            cargo_metadata,
+            cargo_config_extra_env,
+        ) = match join {
+            Ok(it) => it,
+            Err(e) => std::panic::resume_unwind(e),
+        };
 
         let (meta, error) = cargo_metadata.with_context(|| {
             format!(
@@ -391,6 +431,14 @@ impl ProjectWorkspace {
             sysroot.set_workspace(loaded_sysroot);
         }
 
+        if !cargo.requires_rustc_private() {
+            if let Err(e) = &mut rustc {
+                // We don't need the rustc sources here,
+                // so just discard the error.
+                _ = e.take();
+            }
+        }
+
         Ok(ProjectWorkspace {
             kind: ProjectWorkspaceKind::Cargo {
                 cargo,
@@ -413,17 +461,25 @@ impl ProjectWorkspace {
         config: &CargoConfig,
         progress: &(dyn Fn(String) + Sync),
     ) -> ProjectWorkspace {
-        progress("Discovering sysroot".to_owned());
+        progress("discovering sysroot".to_owned());
         let mut sysroot =
             Sysroot::new(project_json.sysroot.clone(), project_json.sysroot_src.clone());
 
         tracing::info!(workspace = %project_json.manifest_or_root(), src_root = ?sysroot.rust_lib_src_root(), root = ?sysroot.root(), "Using sysroot");
-        progress("Querying project metadata".to_owned());
+        progress("querying project metadata".to_owned());
         let sysroot_project = project_json.sysroot_project.take();
         let query_config = QueryConfig::Rustc(&sysroot, project_json.path().as_ref());
         let targets = target_tuple::get(query_config, config.target.as_deref(), &config.extra_env)
             .unwrap_or_default();
         let toolchain = version::get(query_config, &config.extra_env).ok().flatten();
+        let project_root = project_json.project_root();
+        let target_dir = config
+            .target_dir
+            .clone()
+            .or_else(|| {
+                cargo_config_build_target_dir(project_json.manifest()?, &config.extra_env, &sysroot)
+            })
+            .unwrap_or_else(|| project_root.join("target").into());
 
         // We spawn a bunch of processes to query various information about the workspace's
         // toolchain and sysroot
@@ -441,18 +497,14 @@ impl ProjectWorkspace {
                 )
             });
             let loaded_sysroot = s.spawn(|| {
-                let project_root = project_json.project_root();
                 if let Some(sysroot_project) = sysroot_project {
                     sysroot.load_workspace(
                         &RustSourceWorkspaceConfig::Json(*sysroot_project),
+                        config.no_deps,
                         project_root,
                         progress,
                     )
                 } else {
-                    let target_dir = config
-                        .target_dir
-                        .clone()
-                        .unwrap_or_else(|| project_root.join("target").into());
                     sysroot.load_workspace(
                         &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config(
                             config,
@@ -460,6 +512,7 @@ impl ProjectWorkspace {
                             toolchain.clone(),
                             target_dir,
                         )),
+                        config.no_deps,
                         project_root,
                         progress,
                     )
@@ -507,7 +560,12 @@ impl ProjectWorkspace {
             .unwrap_or_default();
         let rustc_cfg = rustc_cfg::get(query_config, None, &config.extra_env);
         let data_layout = target_data_layout::get(query_config, None, &config.extra_env);
-        let target_dir = config.target_dir.clone().unwrap_or_else(|| dir.join("target").into());
+        let target_dir = config
+            .target_dir
+            .clone()
+            .or_else(|| cargo_config_build_target_dir(detached_file, &config.extra_env, &sysroot))
+            .unwrap_or_else(|| dir.join("target").into());
+
         let loaded_sysroot = sysroot.load_workspace(
             &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config(
                 config,
@@ -515,6 +573,7 @@ impl ProjectWorkspace {
                 toolchain.clone(),
                 target_dir.clone(),
             )),
+            config.no_deps,
             dir,
             &|_| (),
         );
@@ -581,10 +640,16 @@ impl ProjectWorkspace {
         match &self.kind {
             ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _, None)), .. }
             | ProjectWorkspaceKind::Cargo { cargo, error: None, .. } => {
-                WorkspaceBuildScripts::run_for_workspace(config, cargo, progress, &self.sysroot)
-                    .with_context(|| {
-                        format!("Failed to run build scripts for {}", cargo.workspace_root())
-                    })
+                WorkspaceBuildScripts::run_for_workspace(
+                    config,
+                    cargo,
+                    progress,
+                    &self.sysroot,
+                    self.toolchain.as_ref(),
+                )
+                .with_context(|| {
+                    format!("Failed to run build scripts for {}", cargo.workspace_root())
+                })
             }
             _ => Ok(WorkspaceBuildScripts::default()),
         }
@@ -683,7 +748,7 @@ impl ProjectWorkspace {
         }
     }
 
-    pub fn find_sysroot_proc_macro_srv(&self) -> anyhow::Result<AbsPathBuf> {
+    pub fn find_sysroot_proc_macro_srv(&self) -> Option<anyhow::Result<AbsPathBuf>> {
         self.sysroot.discover_proc_macro_srv()
     }
 
@@ -1166,14 +1231,10 @@ fn cargo_to_crate_graph(
     // Mapping of a package to its library target
     let mut pkg_to_lib_crate = FxHashMap::default();
     let mut pkg_crates = FxHashMap::default();
-    // Does any crate signal to rust-analyzer that they need the rustc_private crates?
-    let mut has_private = false;
     let workspace_proc_macro_cwd = Arc::new(cargo.workspace_root().to_path_buf());
 
     // Next, create crates for each package, target pair
     for pkg in cargo.packages() {
-        has_private |= cargo[pkg].metadata.rustc_private;
-
         let cfg_options = {
             let mut cfg_options = cfg_options.clone();
 
@@ -1318,7 +1379,7 @@ fn cargo_to_crate_graph(
         add_dep(crate_graph, from, name, to);
     }
 
-    if has_private {
+    if cargo.requires_rustc_private() {
         // If the user provided a path to rustc sources, we add all the rustc_private crates
         // and create dependencies on them for the crates which opt-in to that
         if let Some((rustc_workspace, rustc_build_scripts)) = rustc {
@@ -1584,11 +1645,11 @@ fn add_target_crate_root(
             Some((BuildScriptOutput { proc_macro_dylib_path, .. }, has_errors)) => {
                 match proc_macro_dylib_path {
                     Some(path) => Ok((cargo_name.to_owned(), path.clone())),
-                    None if has_errors => Err("failed to build proc-macro".to_owned()),
-                    None => Err("proc-macro crate build data is missing dylib path".to_owned()),
+                    None if has_errors => Err(ProcMacroLoadingError::FailedToBuild),
+                    None => Err(ProcMacroLoadingError::MissingDylibPath),
                 }
             }
-            None => Err("proc-macro crate is missing its build data".to_owned()),
+            None => Err(ProcMacroLoadingError::NotYetBuilt),
         };
         proc_macros.insert(crate_id, proc_macro);
     }
diff --git a/src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml b/src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml
index 8b03d8f8cc7..5991120a30d 100644
--- a/src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 proc-macro = true
 
 [dependencies]
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
index 5e63521d747..b301a7189b3 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
@@ -13,6 +13,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [[bin]]
 name = "rust-analyzer"
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 740fcd81ea9..f97bf832442 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
@@ -75,8 +75,12 @@ impl Tester {
         };
 
         let mut sysroot = Sysroot::discover(tmp_file.parent().unwrap(), &cargo_config.extra_env);
-        let loaded_sysroot =
-            sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo(), &path, &|_| ());
+        let loaded_sysroot = sysroot.load_workspace(
+            &RustSourceWorkspaceConfig::default_cargo(),
+            false,
+            &path,
+            &|_| (),
+        );
         if let Some(loaded_sysroot) = loaded_sysroot {
             sysroot.set_workspace(loaded_sysroot);
         }
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 05e1b832cd1..51d4c29aa74 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -94,6 +94,8 @@ config_data! {
 
 
 
+        /// Enables highlighting of related return values while the cursor is on any `match`, `if`, or match arm arrow (`=>`).
+        highlightRelated_branchExitPoints_enable: bool = true,
         /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.
         highlightRelated_breakPoints_enable: bool = true,
         /// Enables highlighting of all captures of a closure while the cursor is on the `|` or move keyword of a closure.
@@ -1524,7 +1526,7 @@ impl Config {
         CompletionConfig {
             enable_postfix_completions: self.completion_postfix_enable(source_root).to_owned(),
             enable_imports_on_the_fly: self.completion_autoimport_enable(source_root).to_owned()
-                && self.caps.completion_item_edit_resolve(),
+                && self.caps.has_completion_item_resolve_additionalTextEdits(),
             enable_self_on_the_fly: self.completion_autoself_enable(source_root).to_owned(),
             enable_auto_iter: *self.completion_autoIter_enable(source_root),
             enable_auto_await: *self.completion_autoAwait_enable(source_root),
@@ -1629,6 +1631,7 @@ impl Config {
             exit_points: self.highlightRelated_exitPoints_enable().to_owned(),
             yield_points: self.highlightRelated_yieldPoints_enable().to_owned(),
             closure_captures: self.highlightRelated_closureCaptures_enable().to_owned(),
+            branch_exit_points: self.highlightRelated_branchExitPoints_enable().to_owned(),
         }
     }
 
@@ -2352,10 +2355,6 @@ impl Config {
             .and_then(|it| it.version.as_ref())
     }
 
-    pub fn client_is_helix(&self) -> bool {
-        self.client_info.as_ref().map(|it| it.name == "helix").unwrap_or_default()
-    }
-
     pub fn client_is_neovim(&self) -> bool {
         self.client_info.as_ref().map(|it| it.name == "Neovim").unwrap_or_default()
     }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
index 0e418240db0..91d37bd7c9e 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
@@ -6,6 +6,7 @@ use std::{fmt, io, process::Command, time::Duration};
 use cargo_metadata::PackageId;
 use crossbeam_channel::{Receiver, Sender, select_biased, unbounded};
 use ide_db::FxHashSet;
+use itertools::Itertools;
 use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
 use rustc_hash::FxHashMap;
 use serde::Deserialize as _;
@@ -379,7 +380,11 @@ impl FlycheckActor {
                             package_id = msg.package_id.repr,
                             "artifact received"
                         );
-                        self.report_progress(Progress::DidCheckCrate(msg.target.name));
+                        self.report_progress(Progress::DidCheckCrate(format!(
+                            "{} ({})",
+                            msg.target.name,
+                            msg.target.kind.iter().format_with(", ", |kind, f| f(&kind)),
+                        )));
                         let package_id = Arc::new(msg.package_id);
                         if self.diagnostics_cleared_for.insert(package_id.clone()) {
                             tracing::trace!(
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
index a870232d4a0..62a28a1a685 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
@@ -101,7 +101,7 @@ pub(crate) struct GlobalState {
     pub(crate) last_reported_status: lsp_ext::ServerStatusParams,
 
     // proc macros
-    pub(crate) proc_macro_clients: Arc<[anyhow::Result<ProcMacroClient>]>,
+    pub(crate) proc_macro_clients: Arc<[Option<anyhow::Result<ProcMacroClient>>]>,
     pub(crate) build_deps_changed: bool,
 
     // Flycheck
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs
index 40d05567fcc..aea116e647d 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs
@@ -6,7 +6,7 @@ use std::{
 
 use ide_db::base_db::{
     DbPanicContext,
-    salsa::{self, Cancelled, UnexpectedCycle},
+    salsa::{self, Cancelled},
 };
 use lsp_server::{ExtractError, Response, ResponseError};
 use serde::{Serialize, de::DeserializeOwned};
@@ -350,9 +350,6 @@ where
             if let Some(panic_message) = panic_message {
                 message.push_str(": ");
                 message.push_str(panic_message);
-            } else if let Some(cycle) = panic.downcast_ref::<UnexpectedCycle>() {
-                tracing::error!("{cycle}");
-                message.push_str(": unexpected cycle");
             } else if let Ok(cancelled) = panic.downcast::<Cancelled>() {
                 tracing::error!("Cancellation propagated out of salsa! This is a bug");
                 return Err(HandlerCancelledError::Inner(*cancelled));
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 afd9eff5264..a76a65220d3 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
@@ -2433,17 +2433,14 @@ fn run_rustfmt(
             }
             _ => {
                 // Something else happened - e.g. `rustfmt` is missing or caught a signal
-                Err(LspError::new(
-                    -32900,
-                    format!(
-                        r#"rustfmt exited with:
-                           Status: {}
-                           stdout: {captured_stdout}
-                           stderr: {captured_stderr}"#,
-                        output.status,
-                    ),
-                )
-                .into())
+                tracing::error!(
+                    ?command,
+                    %output.status,
+                    %captured_stdout,
+                    %captured_stderr,
+                    "rustfmt failed"
+                );
+                Ok(None)
             }
         };
     }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
index 04e31f37fd2..f94e7486ff8 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
@@ -42,7 +42,7 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities {
         hover_provider: Some(HoverProviderCapability::Simple(true)),
         completion_provider: Some(CompletionOptions {
             resolve_provider: if config.client_is_neovim() {
-                config.completion_item_edit_resolve().then_some(true)
+                config.has_completion_item_resolve_additionalTextEdits().then_some(true)
             } else {
                 Some(config.caps().completions_resolve_provider())
             },
@@ -207,8 +207,8 @@ impl ClientCapabilities {
         serde_json::from_value(self.0.experimental.as_ref()?.get(index)?.clone()).ok()
     }
 
-    /// Parses client capabilities and returns all completion resolve capabilities rust-analyzer supports.
-    pub fn completion_item_edit_resolve(&self) -> bool {
+    #[allow(non_snake_case)]
+    pub fn has_completion_item_resolve_additionalTextEdits(&self) -> bool {
         (|| {
             Some(
                 self.0
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 4efe330f16a..8a848fb848c 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
@@ -900,14 +900,17 @@ pub(crate) fn folding_range(
         FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment),
         FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports),
         FoldKind::Region => Some(lsp_types::FoldingRangeKind::Region),
-        FoldKind::Mods
+        FoldKind::Modules
         | FoldKind::Block
         | FoldKind::ArgList
         | FoldKind::Consts
         | FoldKind::Statics
+        | FoldKind::TypeAliases
         | FoldKind::WhereClause
         | FoldKind::ReturnType
         | FoldKind::Array
+        | FoldKind::TraitAliases
+        | FoldKind::ExternCrates
         | FoldKind::MatchArm => None,
     };
 
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 0c0438c4b8f..00cf890510d 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
@@ -783,9 +783,14 @@ impl GlobalState {
                             DiscoverProjectParam::Path(it) => DiscoverArgument::Path(it),
                         };
 
-                        let handle =
-                            discover.spawn(arg, &std::env::current_dir().unwrap()).unwrap();
-                        self.discover_handle = Some(handle);
+                        let handle = discover.spawn(
+                            arg,
+                            &std::env::current_dir()
+                                .expect("Failed to get cwd during project discovery"),
+                        );
+                        self.discover_handle = Some(handle.unwrap_or_else(|e| {
+                            panic!("Failed to spawn project discovery command: {e}")
+                        }));
                     }
                 }
             }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index 189d95ec7ed..e798aa6a8a6 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -18,7 +18,7 @@ use std::{iter, mem};
 use hir::{ChangeWithProcMacros, ProcMacrosBuilder, db::DefDatabase};
 use ide_db::{
     FxHashMap,
-    base_db::{CrateGraphBuilder, ProcMacroPaths, salsa::Durability},
+    base_db::{CrateGraphBuilder, ProcMacroLoadingError, ProcMacroPaths, salsa::Durability},
 };
 use itertools::Itertools;
 use load_cargo::{ProjectFolders, load_proc_macro};
@@ -194,8 +194,7 @@ impl GlobalState {
                 format_to!(message, "{e}");
             });
 
-            let proc_macro_clients =
-                self.proc_macro_clients.iter().map(Some).chain(iter::repeat_with(|| None));
+            let proc_macro_clients = self.proc_macro_clients.iter().chain(iter::repeat(&None));
 
             for (ws, proc_macro_client) in self.workspaces.iter().zip(proc_macro_clients) {
                 if let ProjectWorkspaceKind::Cargo { error: Some(error), .. }
@@ -252,7 +251,8 @@ impl GlobalState {
                             message.push_str("\n\n");
                         }
                     }
-                    _ => (),
+                    // sysroot was explicitly not set so we didn't discover a server
+                    None => {}
                 }
             }
         }
@@ -419,16 +419,13 @@ impl GlobalState {
             };
 
             let mut builder = ProcMacrosBuilder::default();
-            let proc_macro_clients = proc_macro_clients
-                .iter()
-                .map(|res| res.as_ref().map_err(|e| e.to_string()))
-                .chain(iter::repeat_with(|| Err("proc-macro-srv is not running".into())));
+            let proc_macro_clients = proc_macro_clients.iter().chain(iter::repeat(&None));
             for (client, paths) in proc_macro_clients.zip(paths) {
                 for (crate_id, res) in paths.iter() {
                     let expansion_res = match client {
-                        Ok(client) => match res {
+                        Some(Ok(client)) => match res {
                             Ok((crate_name, path)) => {
-                                progress(path.to_string());
+                                progress(format!("loading proc-macros: {path}"));
                                 let ignored_proc_macros = ignored_proc_macros
                                     .iter()
                                     .find_map(|(name, macros)| {
@@ -438,9 +435,14 @@ impl GlobalState {
 
                                 load_proc_macro(client, path, ignored_proc_macros)
                             }
-                            Err(e) => Err((e.clone(), true)),
+                            Err(e) => Err(e.clone()),
                         },
-                        Err(ref e) => Err((e.clone(), true)),
+                        Some(Err(e)) => Err(ProcMacroLoadingError::ProcMacroSrvError(
+                            e.to_string().into_boxed_str(),
+                        )),
+                        None => Err(ProcMacroLoadingError::ProcMacroSrvError(
+                            "proc-macro-srv is not running".into(),
+                        )),
                     };
                     builder.insert(*crate_id, expansion_res)
                 }
@@ -655,7 +657,10 @@ impl GlobalState {
             self.proc_macro_clients = Arc::from_iter(self.workspaces.iter().map(|ws| {
                 let path = match self.config.proc_macro_srv() {
                     Some(path) => path,
-                    None => ws.find_sysroot_proc_macro_srv()?,
+                    None => match ws.find_sysroot_proc_macro_srv()? {
+                        Ok(path) => path,
+                        Err(e) => return Some(Err(e)),
+                    },
                 };
 
                 let env: FxHashMap<_, _> = match &ws.kind {
@@ -682,14 +687,14 @@ impl GlobalState {
                 };
                 info!("Using proc-macro server at {path}");
 
-                ProcMacroClient::spawn(&path, &env).map_err(|err| {
+                Some(ProcMacroClient::spawn(&path, &env).map_err(|err| {
                     tracing::error!(
                         "Failed to run proc-macro server from path {path}, error: {err:?}",
                     );
                     anyhow::format_err!(
                         "Failed to run proc-macro server from path {path}, error: {err:?}",
                     )
-                })
+                }))
             }))
         }
 
@@ -753,14 +758,14 @@ impl GlobalState {
                 change.set_proc_macros(
                     crate_graph
                         .iter()
-                        .map(|id| (id, Err(("proc-macro has not been built yet".to_owned(), true))))
+                        .map(|id| (id, Err(ProcMacroLoadingError::NotYetBuilt)))
                         .collect(),
                 );
             } else {
                 change.set_proc_macros(
                     crate_graph
                         .iter()
-                        .map(|id| (id, Err(("proc-macro expansion is disabled".to_owned(), false))))
+                        .map(|id| (id, Err(ProcMacroLoadingError::Disabled)))
                         .collect(),
                 );
             }
diff --git a/src/tools/rust-analyzer/crates/span/src/ast_id.rs b/src/tools/rust-analyzer/crates/span/src/ast_id.rs
index 8e959711981..121d2e33243 100644
--- a/src/tools/rust-analyzer/crates/span/src/ast_id.rs
+++ b/src/tools/rust-analyzer/crates/span/src/ast_id.rs
@@ -107,9 +107,10 @@ impl fmt::Debug for ErasedFileAstId {
 }
 
 #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
+#[repr(u8)]
 enum ErasedFileAstIdKind {
     /// This needs to not change because it's depended upon by the proc macro server.
-    Fixup,
+    Fixup = 0,
     // The following are associated with `ErasedHasNameFileAstId`.
     Enum,
     Struct,
@@ -413,9 +414,9 @@ impl ErasedAstIdNextIndexMap {
 }
 
 macro_rules! register_enum_ast_id {
-    (impl AstIdNode for $($ident:ident),+ ) => {
+    (impl $AstIdNode:ident for $($ident:ident),+ ) => {
         $(
-            impl AstIdNode for ast::$ident {}
+            impl $AstIdNode for ast::$ident {}
         )+
     };
 }
@@ -426,9 +427,9 @@ register_enum_ast_id! {
 }
 
 macro_rules! register_has_name_ast_id {
-    (impl AstIdNode for $($ident:ident = $name_method:ident),+ ) => {
+    (impl $AstIdNode:ident for $($ident:ident = $name_method:ident),+ ) => {
         $(
-            impl AstIdNode for ast::$ident {}
+            impl $AstIdNode for ast::$ident {}
         )+
 
         fn has_name_ast_id(node: &SyntaxNode, index_map: &mut ErasedAstIdNextIndexMap) -> Option<ErasedFileAstId> {
@@ -472,9 +473,9 @@ register_has_name_ast_id! {
 }
 
 macro_rules! register_assoc_item_ast_id {
-    (impl AstIdNode for $($ident:ident = $name_callback:expr),+ ) => {
+    (impl $AstIdNode:ident for $($ident:ident = $name_callback:expr),+ ) => {
         $(
-            impl AstIdNode for ast::$ident {}
+            impl $AstIdNode for ast::$ident {}
         )+
 
         fn assoc_item_ast_id(
diff --git a/src/tools/rust-analyzer/crates/span/src/hygiene.rs b/src/tools/rust-analyzer/crates/span/src/hygiene.rs
index 7bb88ac3658..aef3fbf0517 100644
--- a/src/tools/rust-analyzer/crates/span/src/hygiene.rs
+++ b/src/tools/rust-analyzer/crates/span/src/hygiene.rs
@@ -97,6 +97,7 @@ const _: () = {
         const LOCATION: salsa::plumbing::Location =
             salsa::plumbing::Location { file: file!(), line: line!() };
         const DEBUG_NAME: &'static str = "SyntaxContextData";
+        const REVISIONS: std::num::NonZeroUsize = std::num::NonZeroUsize::MAX;
         type Fields<'a> = SyntaxContextData;
         type Struct<'a> = SyntaxContext;
     }
@@ -108,7 +109,9 @@ const _: () = {
             static CACHE: zalsa_::IngredientCache<zalsa_struct_::IngredientImpl<SyntaxContext>> =
                 zalsa_::IngredientCache::new();
             CACHE.get_or_create(db.zalsa(), || {
-                db.zalsa().add_or_lookup_jar_by_type::<zalsa_struct_::JarImpl<SyntaxContext>>()
+                db.zalsa()
+                    .lookup_jar_by_type::<zalsa_struct_::JarImpl<SyntaxContext>>()
+                    .get_or_create()
             })
         }
     }
@@ -130,9 +133,12 @@ const _: () = {
         type MemoIngredientMap = salsa::plumbing::MemoIngredientSingletonIndex;
 
         fn lookup_or_create_ingredient_index(
-            aux: &salsa::plumbing::Zalsa,
+            zalsa: &salsa::plumbing::Zalsa,
         ) -> salsa::plumbing::IngredientIndices {
-            aux.add_or_lookup_jar_by_type::<zalsa_struct_::JarImpl<SyntaxContext>>().into()
+            zalsa
+                .lookup_jar_by_type::<zalsa_struct_::JarImpl<SyntaxContext>>()
+                .get_or_create()
+                .into()
         }
 
         #[inline]
@@ -326,14 +332,14 @@ impl<'db> SyntaxContext {
             None
         } else {
             // SAFETY: By our invariant, this is either a root (which we verified it's not) or a valid `salsa::Id`.
-            unsafe { Some(salsa::Id::from_u32(self.0)) }
+            unsafe { Some(salsa::Id::from_index(self.0)) }
         }
     }
 
     #[inline]
     fn from_salsa_id(id: salsa::Id) -> Self {
         // SAFETY: This comes from a Salsa ID.
-        unsafe { Self::from_u32(id.as_u32()) }
+        unsafe { Self::from_u32(id.index()) }
     }
 
     #[inline]
diff --git a/src/tools/rust-analyzer/crates/stdx/Cargo.toml b/src/tools/rust-analyzer/crates/stdx/Cargo.toml
index a6d57816608..2c19f00f082 100644
--- a/src/tools/rust-analyzer/crates/stdx/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/stdx/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 backtrace = { version = "0.3.75", optional = true }
diff --git a/src/tools/rust-analyzer/crates/syntax-bridge/Cargo.toml b/src/tools/rust-analyzer/crates/syntax-bridge/Cargo.toml
index cccd41d5429..b0fd40ff59f 100644
--- a/src/tools/rust-analyzer/crates/syntax-bridge/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/syntax-bridge/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 rustc-hash.workspace = true
diff --git a/src/tools/rust-analyzer/crates/syntax/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/Cargo.toml
index 9d3aaa8d4e3..1ee93013e3e 100644
--- a/src/tools/rust-analyzer/crates/syntax/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/syntax/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 either.workspace = true
diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram
index c81da06682e..3f439472337 100644
--- a/src/tools/rust-analyzer/crates/syntax/rust.ungram
+++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram
@@ -669,7 +669,7 @@ TypeBoundList =
 
 TypeBound =
   Lifetime
-| ('~' 'const' | 'const')? 'async'? '?'? Type
+| ('~' 'const' | '[' 'const' ']' | 'const')? 'async'? '?'? Type
 | 'use' UseBoundGenericArgs
 
 UseBoundGenericArgs =
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
index 04c7e8a578c..79a9f4da338 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
@@ -1766,6 +1766,10 @@ impl TypeBound {
         support::child(&self.syntax)
     }
     #[inline]
+    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
+    #[inline]
+    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
+    #[inline]
     pub fn question_mark_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![?]) }
     #[inline]
     pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
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 955aadaa25d..309332873cb 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
@@ -842,9 +842,10 @@ pub fn ref_pat(pat: ast::Pat) -> ast::RefPat {
 }
 
 pub fn match_arm(pat: ast::Pat, guard: Option<ast::MatchGuard>, expr: ast::Expr) -> ast::MatchArm {
+    let comma_str = if expr.is_block_like() { "" } else { "," };
     return match guard {
-        Some(guard) => from_text(&format!("{pat} {guard} => {expr}")),
-        None => from_text(&format!("{pat} => {expr}")),
+        Some(guard) => from_text(&format!("{pat} {guard} => {expr}{comma_str}")),
+        None => from_text(&format!("{pat} => {expr}{comma_str}")),
     };
 
     fn from_text(text: &str) -> ast::MatchArm {
@@ -877,7 +878,7 @@ pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::Mat
     let arms_str = arms.into_iter().fold(String::new(), |mut acc, arm| {
         let needs_comma =
             arm.comma_token().is_none() && arm.expr().is_none_or(|it| !it.is_block_like());
-        let comma = if needs_comma { "," } else { "" };
+        let comma = if needs_comma && arm.comma_token().is_none() { "," } else { "" };
         let arm = arm.syntax();
         format_to_acc!(acc, "    {arm}{comma}\n")
     });
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 429e51ba362..17cc5f9c057 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
@@ -1212,6 +1212,43 @@ impl SyntaxFactory {
         ast
     }
 
+    pub fn attr_outer(&self, meta: ast::Meta) -> ast::Attr {
+        let ast = make::attr_outer(meta.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(meta.syntax().clone(), ast.meta().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn attr_inner(&self, meta: ast::Meta) -> ast::Attr {
+        let ast = make::attr_inner(meta.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(meta.syntax().clone(), ast.meta().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn meta_token_tree(&self, path: ast::Path, tt: ast::TokenTree) -> ast::Meta {
+        let ast = make::meta_token_tree(path.clone(), tt.clone()).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_node(tt.syntax().clone(), ast.token_tree().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
     pub fn token_tree(
         &self,
         delimiter: SyntaxKind,
@@ -1242,6 +1279,10 @@ impl SyntaxFactory {
     pub fn whitespace(&self, text: &str) -> SyntaxToken {
         make::tokens::whitespace(text)
     }
+
+    pub fn ident(&self, text: &str) -> SyntaxToken {
+        make::tokens::ident(text)
+    }
 }
 
 // `ext` constructors
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs
index ced3b713d8d..4afdda78a0e 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs
@@ -1,9 +1,11 @@
 //! There are many AstNodes, but only a few tokens, so we hand-write them here.
 
+use std::ops::Range;
 use std::{borrow::Cow, num::ParseIntError};
 
 use rustc_literal_escaper::{
-    EscapeError, MixedUnit, Mode, unescape_byte, unescape_char, unescape_mixed, unescape_unicode,
+    EscapeError, MixedUnit, unescape_byte, unescape_byte_str, unescape_c_str, unescape_char,
+    unescape_str,
 };
 use stdx::always;
 
@@ -150,7 +152,7 @@ impl QuoteOffsets {
 
 pub trait IsString: AstToken {
     const RAW_PREFIX: &'static str;
-    const MODE: Mode;
+    fn unescape(s: &str, callback: impl FnMut(Range<usize>, Result<char, EscapeError>));
     fn is_raw(&self) -> bool {
         self.text().starts_with(Self::RAW_PREFIX)
     }
@@ -185,7 +187,7 @@ pub trait IsString: AstToken {
         let text = &self.text()[text_range_no_quotes - start];
         let offset = text_range_no_quotes.start() - start;
 
-        unescape_unicode(text, Self::MODE, &mut |range, unescaped_char| {
+        Self::unescape(text, &mut |range: Range<usize>, unescaped_char| {
             if let Some((s, e)) = range.start.try_into().ok().zip(range.end.try_into().ok()) {
                 cb(TextRange::new(s, e) + offset, unescaped_char);
             }
@@ -203,7 +205,9 @@ pub trait IsString: AstToken {
 
 impl IsString for ast::String {
     const RAW_PREFIX: &'static str = "r";
-    const MODE: Mode = Mode::Str;
+    fn unescape(s: &str, cb: impl FnMut(Range<usize>, Result<char, EscapeError>)) {
+        unescape_str(s, cb)
+    }
 }
 
 impl ast::String {
@@ -218,20 +222,19 @@ impl ast::String {
         let mut buf = String::new();
         let mut prev_end = 0;
         let mut has_error = None;
-        unescape_unicode(text, Self::MODE, &mut |char_range, unescaped_char| match (
-            unescaped_char,
-            buf.capacity() == 0,
-        ) {
-            (Ok(c), false) => buf.push(c),
-            (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => {
-                prev_end = char_range.end
-            }
-            (Ok(c), true) => {
-                buf.reserve_exact(text.len());
-                buf.push_str(&text[..prev_end]);
-                buf.push(c);
+        unescape_str(text, |char_range, unescaped_char| {
+            match (unescaped_char, buf.capacity() == 0) {
+                (Ok(c), false) => buf.push(c),
+                (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => {
+                    prev_end = char_range.end
+                }
+                (Ok(c), true) => {
+                    buf.reserve_exact(text.len());
+                    buf.push_str(&text[..prev_end]);
+                    buf.push(c);
+                }
+                (Err(e), _) => has_error = Some(e),
             }
-            (Err(e), _) => has_error = Some(e),
         });
 
         match (has_error, buf.capacity() == 0) {
@@ -244,7 +247,9 @@ impl ast::String {
 
 impl IsString for ast::ByteString {
     const RAW_PREFIX: &'static str = "br";
-    const MODE: Mode = Mode::ByteStr;
+    fn unescape(s: &str, mut callback: impl FnMut(Range<usize>, Result<char, EscapeError>)) {
+        unescape_byte_str(s, |range, res| callback(range, res.map(char::from)))
+    }
 }
 
 impl ast::ByteString {
@@ -259,20 +264,19 @@ impl ast::ByteString {
         let mut buf: Vec<u8> = Vec::new();
         let mut prev_end = 0;
         let mut has_error = None;
-        unescape_unicode(text, Self::MODE, &mut |char_range, unescaped_char| match (
-            unescaped_char,
-            buf.capacity() == 0,
-        ) {
-            (Ok(c), false) => buf.push(c as u8),
-            (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => {
-                prev_end = char_range.end
-            }
-            (Ok(c), true) => {
-                buf.reserve_exact(text.len());
-                buf.extend_from_slice(&text.as_bytes()[..prev_end]);
-                buf.push(c as u8);
+        unescape_byte_str(text, |char_range, unescaped_byte| {
+            match (unescaped_byte, buf.capacity() == 0) {
+                (Ok(b), false) => buf.push(b),
+                (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => {
+                    prev_end = char_range.end
+                }
+                (Ok(b), true) => {
+                    buf.reserve_exact(text.len());
+                    buf.extend_from_slice(&text.as_bytes()[..prev_end]);
+                    buf.push(b);
+                }
+                (Err(e), _) => has_error = Some(e),
             }
-            (Err(e), _) => has_error = Some(e),
         });
 
         match (has_error, buf.capacity() == 0) {
@@ -285,25 +289,10 @@ impl ast::ByteString {
 
 impl IsString for ast::CString {
     const RAW_PREFIX: &'static str = "cr";
-    const MODE: Mode = Mode::CStr;
-
-    fn escaped_char_ranges(&self, cb: &mut dyn FnMut(TextRange, Result<char, EscapeError>)) {
-        let text_range_no_quotes = match self.text_range_between_quotes() {
-            Some(it) => it,
-            None => return,
-        };
-
-        let start = self.syntax().text_range().start();
-        let text = &self.text()[text_range_no_quotes - start];
-        let offset = text_range_no_quotes.start() - start;
-
-        unescape_mixed(text, Self::MODE, &mut |range, unescaped_char| {
-            let text_range =
-                TextRange::new(range.start.try_into().unwrap(), range.end.try_into().unwrap());
-            // XXX: This method should only be used for highlighting ranges. The unescaped
-            // char/byte is not used. For simplicity, we return an arbitrary placeholder char.
-            cb(text_range + offset, unescaped_char.map(|_| ' '));
-        });
+    // NOTE: This method should only be used for highlighting ranges. The unescaped
+    // char/byte is not used. For simplicity, we return an arbitrary placeholder char.
+    fn unescape(s: &str, mut callback: impl FnMut(Range<usize>, Result<char, EscapeError>)) {
+        unescape_c_str(s, |range, _res| callback(range, Ok('_')))
     }
 }
 
@@ -323,10 +312,7 @@ impl ast::CString {
             MixedUnit::Char(c) => buf.extend(c.encode_utf8(&mut [0; 4]).as_bytes()),
             MixedUnit::HighByte(b) => buf.push(b),
         };
-        unescape_mixed(text, Self::MODE, &mut |char_range, unescaped| match (
-            unescaped,
-            buf.capacity() == 0,
-        ) {
+        unescape_c_str(text, |char_range, unescaped| match (unescaped, buf.capacity() == 0) {
             (Ok(u), false) => extend_unit(&mut buf, u),
             (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => {
                 prev_end = char_range.end
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 31caf618be9..3fa584850f7 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs
@@ -435,7 +435,7 @@ mod tests {
             _ => {
                 let var_name = 2 + 2;
                 (var_name, true)
-            }"#]];
+            },"#]];
         expect.assert_eq(&edit.new_root.to_string());
 
         assert_eq!(edit.find_annotation(placeholder_snippet).len(), 2);
diff --git a/src/tools/rust-analyzer/crates/syntax/src/validation.rs b/src/tools/rust-analyzer/crates/syntax/src/validation.rs
index 5bfeb3bff87..4180f9cd185 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/validation.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/validation.rs
@@ -6,7 +6,9 @@ mod block;
 
 use itertools::Itertools;
 use rowan::Direction;
-use rustc_literal_escaper::{self, EscapeError, Mode, unescape_mixed, unescape_unicode};
+use rustc_literal_escaper::{
+    EscapeError, unescape_byte, unescape_byte_str, unescape_c_str, unescape_char, unescape_str,
+};
 
 use crate::{
     AstNode, SyntaxError,
@@ -47,7 +49,7 @@ pub(crate) fn validate(root: &SyntaxNode, errors: &mut Vec<SyntaxError>) {
 }
 
 fn rustc_unescape_error_to_string(err: EscapeError) -> (&'static str, bool) {
-    use rustc_literal_escaper::EscapeError as EE;
+    use EscapeError as EE;
 
     #[rustfmt::skip]
     let err_message = match err {
@@ -142,7 +144,7 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) {
         ast::LiteralKind::String(s) => {
             if !s.is_raw() {
                 if let Some(without_quotes) = unquote(text, 1, '"') {
-                    unescape_unicode(without_quotes, Mode::Str, &mut |range, char| {
+                    unescape_str(without_quotes, |range, char| {
                         if let Err(err) = char {
                             push_err(1, range.start, err);
                         }
@@ -153,7 +155,7 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) {
         ast::LiteralKind::ByteString(s) => {
             if !s.is_raw() {
                 if let Some(without_quotes) = unquote(text, 2, '"') {
-                    unescape_unicode(without_quotes, Mode::ByteStr, &mut |range, char| {
+                    unescape_byte_str(without_quotes, |range, char| {
                         if let Err(err) = char {
                             push_err(1, range.start, err);
                         }
@@ -164,7 +166,7 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) {
         ast::LiteralKind::CString(s) => {
             if !s.is_raw() {
                 if let Some(without_quotes) = unquote(text, 2, '"') {
-                    unescape_mixed(without_quotes, Mode::CStr, &mut |range, char| {
+                    unescape_c_str(without_quotes, |range, char| {
                         if let Err(err) = char {
                             push_err(1, range.start, err);
                         }
@@ -174,20 +176,16 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) {
         }
         ast::LiteralKind::Char(_) => {
             if let Some(without_quotes) = unquote(text, 1, '\'') {
-                unescape_unicode(without_quotes, Mode::Char, &mut |range, char| {
-                    if let Err(err) = char {
-                        push_err(1, range.start, err);
-                    }
-                });
+                if let Err(err) = unescape_char(without_quotes) {
+                    push_err(1, 0, err);
+                }
             }
         }
         ast::LiteralKind::Byte(_) => {
             if let Some(without_quotes) = unquote(text, 2, '\'') {
-                unescape_unicode(without_quotes, Mode::Byte, &mut |range, char| {
-                    if let Err(err) = char {
-                        push_err(2, range.start, err);
-                    }
-                });
+                if let Err(err) = unescape_byte(without_quotes) {
+                    push_err(2, 0, err);
+                }
             }
         }
         ast::LiteralKind::IntNumber(_)
diff --git a/src/tools/rust-analyzer/crates/test-utils/Cargo.toml b/src/tools/rust-analyzer/crates/test-utils/Cargo.toml
index c27e850ce7f..6d1930aa268 100644
--- a/src/tools/rust-analyzer/crates/test-utils/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/test-utils/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 # Avoid adding deps here, this crate is widely used in tests it should compile fast!
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 1d821e96e55..e830c6a7cf6 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
@@ -435,14 +435,16 @@ impl MiniCore {
                 continue;
             }
 
-            let mut active_line_region = false;
-            let mut inactive_line_region = false;
+            let mut active_line_region = 0;
+            let mut inactive_line_region = 0;
             if let Some(idx) = trimmed.find("// :!") {
-                inactive_line_region = true;
-                inactive_regions.push(&trimmed[idx + "// :!".len()..]);
+                let regions = trimmed[idx + "// :!".len()..].split(", ");
+                inactive_line_region += regions.clone().count();
+                inactive_regions.extend(regions);
             } else if let Some(idx) = trimmed.find("// :") {
-                active_line_region = true;
-                active_regions.push(&trimmed[idx + "// :".len()..]);
+                let regions = trimmed[idx + "// :".len()..].split(", ");
+                active_line_region += regions.clone().count();
+                active_regions.extend(regions);
             }
 
             let mut keep = true;
@@ -462,11 +464,11 @@ impl MiniCore {
             if keep {
                 buf.push_str(line);
             }
-            if active_line_region {
-                active_regions.pop().unwrap();
+            if active_line_region > 0 {
+                active_regions.drain(active_regions.len() - active_line_region..);
             }
-            if inactive_line_region {
-                inactive_regions.pop().unwrap();
+            if inactive_line_region > 0 {
+                inactive_regions.drain(inactive_regions.len() - active_line_region..);
             }
         }
 
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 d13a81d287f..dc1eba1a1ab 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
@@ -11,10 +11,13 @@
 //!     add:
 //!     asm:
 //!     assert:
+//!     as_mut: sized
 //!     as_ref: sized
 //!     async_fn: fn, tuple, future, copy
 //!     bool_impl: option, fn
 //!     builtin_impls:
+//!     borrow: sized
+//!     borrow_mut: borrow
 //!     cell: copy, drop
 //!     clone: sized
 //!     coerce_pointee: derive, sized, unsize, coerce_unsized, dispatch_from_dyn
@@ -26,7 +29,7 @@
 //!     deref: sized
 //!     derive:
 //!     discriminant:
-//!     drop:
+//!     drop: sized
 //!     env: option
 //!     eq: sized
 //!     error: fmt
@@ -37,7 +40,7 @@
 //!     future: pin
 //!     coroutine: pin
 //!     dispatch_from_dyn: unsize, pin
-//!     hash:
+//!     hash: sized
 //!     include:
 //!     index: sized
 //!     infallible:
@@ -77,33 +80,46 @@
 
 pub mod marker {
     // region:sized
+    #[lang = "pointee_sized"]
+    #[fundamental]
+    #[rustc_specialization_trait]
+    #[rustc_coinductive]
+    pub trait PointeeSized {}
+
+    #[lang = "meta_sized"]
+    #[fundamental]
+    #[rustc_specialization_trait]
+    #[rustc_coinductive]
+    pub trait MetaSized: PointeeSized {}
+
     #[lang = "sized"]
     #[fundamental]
     #[rustc_specialization_trait]
-    pub trait Sized {}
+    #[rustc_coinductive]
+    pub trait Sized: MetaSized {}
     // endregion:sized
 
     // region:send
     pub unsafe auto trait Send {}
 
-    impl<T: ?Sized> !Send for *const T {}
-    impl<T: ?Sized> !Send for *mut T {}
+    impl<T: PointeeSized> !Send for *const T {}
+    impl<T: PointeeSized> !Send for *mut T {}
     // region:sync
-    unsafe impl<T: Sync + ?Sized> Send for &T {}
-    unsafe impl<T: Send + ?Sized> Send for &mut T {}
+    unsafe impl<T: Sync + PointeeSized> Send for &T {}
+    unsafe impl<T: Send + PointeeSized> Send for &mut T {}
     // endregion:sync
     // endregion:send
 
     // region:sync
     pub unsafe auto trait Sync {}
 
-    impl<T: ?Sized> !Sync for *const T {}
-    impl<T: ?Sized> !Sync for *mut T {}
+    impl<T: PointeeSized> !Sync for *const T {}
+    impl<T: PointeeSized> !Sync for *mut T {}
     // endregion:sync
 
     // region:unsize
     #[lang = "unsize"]
-    pub trait Unsize<T: ?Sized> {}
+    pub trait Unsize<T: PointeeSized>: PointeeSized {}
     // endregion:unsize
 
     // region:unpin
@@ -120,7 +136,7 @@ pub mod marker {
     // endregion:derive
 
     mod copy_impls {
-        use super::Copy;
+        use super::{Copy, PointeeSized};
 
         macro_rules! impl_copy {
             ($($t:ty)*) => {
@@ -137,9 +153,9 @@ pub mod marker {
             bool char
         }
 
-        impl<T: ?Sized> Copy for *const T {}
-        impl<T: ?Sized> Copy for *mut T {}
-        impl<T: ?Sized> Copy for &T {}
+        impl<T: PointeeSized> Copy for *const T {}
+        impl<T: PointeeSized> Copy for *mut T {}
+        impl<T: PointeeSized> Copy for &T {}
         impl Copy for ! {}
     }
     // endregion:copy
@@ -151,7 +167,7 @@ pub mod marker {
 
     // region:phantom_data
     #[lang = "phantom_data"]
-    pub struct PhantomData<T: ?Sized>;
+    pub struct PhantomData<T: PointeeSized>;
     // endregion:phantom_data
 
     // region:discriminant
@@ -206,25 +222,31 @@ pub mod default {
 
 // region:hash
 pub mod hash {
+    use crate::marker::PointeeSized;
+
     pub trait Hasher {}
 
-    pub trait Hash {
+    pub trait Hash: PointeeSized {
         fn hash<H: Hasher>(&self, state: &mut H);
     }
 
     // region:derive
-    #[rustc_builtin_macro]
-    pub macro Hash($item:item) {}
+    pub(crate) mod derive {
+        #[rustc_builtin_macro]
+        pub macro Hash($item:item) {}
+    }
+    pub use derive::Hash;
     // endregion:derive
 }
 // endregion:hash
 
 // region:cell
 pub mod cell {
+    use crate::marker::PointeeSized;
     use crate::mem;
 
     #[lang = "unsafe_cell"]
-    pub struct UnsafeCell<T: ?Sized> {
+    pub struct UnsafeCell<T: PointeeSized> {
         value: T,
     }
 
@@ -238,7 +260,7 @@ pub mod cell {
         }
     }
 
-    pub struct Cell<T: ?Sized> {
+    pub struct Cell<T: PointeeSized> {
         value: UnsafeCell<T>,
     }
 
@@ -357,20 +379,41 @@ pub mod convert {
     // endregion:from
 
     // region:as_ref
-    pub trait AsRef<T: ?Sized> {
+    pub trait AsRef<T: crate::marker::PointeeSized>: crate::marker::PointeeSized {
         fn as_ref(&self) -> &T;
     }
     // endregion:as_ref
+    // region:as_mut
+    pub trait AsMut<T: crate::marker::PointeeSized>: crate::marker::PointeeSized {
+        fn as_mut(&mut self) -> &mut T;
+    }
+    // endregion:as_mut
     // region:infallible
     pub enum Infallible {}
     // endregion:infallible
 }
 
+pub mod borrow {
+    // region:borrow
+    pub trait Borrow<Borrowed: ?Sized> {
+        fn borrow(&self) -> &Borrowed;
+    }
+    // endregion:borrow
+
+    // region:borrow_mut
+    pub trait BorrowMut<Borrowed: ?Sized>: Borrow<Borrowed> {
+        fn borrow_mut(&mut self) -> &mut Borrowed;
+    }
+    // endregion:borrow_mut
+}
+
 pub mod mem {
     // region:manually_drop
+    use crate::marker::PointeeSized;
+
     #[lang = "manually_drop"]
     #[repr(transparent)]
-    pub struct ManuallyDrop<T: ?Sized> {
+    pub struct ManuallyDrop<T: PointeeSized> {
         value: T,
     }
 
@@ -381,7 +424,7 @@ pub mod mem {
     }
 
     // region:deref
-    impl<T: ?Sized> crate::ops::Deref for ManuallyDrop<T> {
+    impl<T: PointeeSized> crate::ops::Deref for ManuallyDrop<T> {
         type Target = T;
         fn deref(&self) -> &T {
             &self.value
@@ -428,7 +471,7 @@ pub mod mem {
 pub mod ptr {
     // region:drop
     #[lang = "drop_in_place"]
-    pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+    pub unsafe fn drop_in_place<T: crate::marker::PointeeSized>(to_drop: *mut T) {
         unsafe { drop_in_place(to_drop) }
     }
     pub const unsafe fn read<T>(src: *const T) -> T {
@@ -444,7 +487,7 @@ pub mod ptr {
     // region:pointee
     #[lang = "pointee_trait"]
     #[rustc_deny_explicit_impl(implement_via_object = false)]
-    pub trait Pointee {
+    pub trait Pointee: crate::marker::PointeeSized {
         #[lang = "metadata_type"]
         type Metadata: Copy + Send + Sync + Ord + Hash + Unpin;
     }
@@ -452,12 +495,14 @@ pub mod ptr {
     // region:non_null
     #[rustc_layout_scalar_valid_range_start(1)]
     #[rustc_nonnull_optimization_guaranteed]
-    pub struct NonNull<T: ?Sized> {
+    pub struct NonNull<T: crate::marker::PointeeSized> {
         pointer: *const T,
     }
     // region:coerce_unsized
-    impl<T: ?Sized, U: ?Sized> crate::ops::CoerceUnsized<NonNull<U>> for NonNull<T> where
-        T: crate::marker::Unsize<U>
+    impl<T: crate::marker::PointeeSized, U: crate::marker::PointeeSized>
+        crate::ops::CoerceUnsized<NonNull<U>> for NonNull<T>
+    where
+        T: crate::marker::Unsize<U>,
     {
     }
     // endregion:coerce_unsized
@@ -478,42 +523,44 @@ pub mod ptr {
 pub mod ops {
     // region:coerce_unsized
     mod unsize {
-        use crate::marker::Unsize;
+        use crate::marker::{PointeeSized, Unsize};
 
         #[lang = "coerce_unsized"]
-        pub trait CoerceUnsized<T: ?Sized> {}
+        pub trait CoerceUnsized<T> {}
 
-        impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
-        impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {}
-        impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {}
-        impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {}
+        impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a mut U> for &'a mut T {}
+        impl<'a, 'b: 'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a U> for &'b mut T {}
+        impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*mut U> for &'a mut T {}
+        impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*const U> for &'a mut T {}
 
-        impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
-        impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a T {}
+        impl<'a, 'b: 'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a U> for &'b T {}
+        impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*const U> for &'a T {}
 
-        impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
-        impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {}
-        impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
+        impl<T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*mut U> for *mut T {}
+        impl<T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*const U> for *mut T {}
+        impl<T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*const U> for *const T {}
     }
     pub use self::unsize::CoerceUnsized;
     // endregion:coerce_unsized
 
     // region:deref
     mod deref {
+        use crate::marker::PointeeSized;
+
         #[lang = "deref"]
-        pub trait Deref {
+        pub trait Deref: PointeeSized {
             #[lang = "deref_target"]
             type Target: ?Sized;
             fn deref(&self) -> &Self::Target;
         }
 
-        impl<T: ?Sized> Deref for &T {
+        impl<T: PointeeSized> Deref for &T {
             type Target = T;
             fn deref(&self) -> &T {
                 loop {}
             }
         }
-        impl<T: ?Sized> Deref for &mut T {
+        impl<T: PointeeSized> Deref for &mut T {
             type Target = T;
             fn deref(&self) -> &T {
                 loop {}
@@ -521,19 +568,19 @@ pub mod ops {
         }
         // region:deref_mut
         #[lang = "deref_mut"]
-        pub trait DerefMut: Deref {
+        pub trait DerefMut: Deref + PointeeSized {
             fn deref_mut(&mut self) -> &mut Self::Target;
         }
         // endregion:deref_mut
 
         // region:receiver
         #[lang = "receiver"]
-        pub trait Receiver {
+        pub trait Receiver: PointeeSized {
             #[lang = "receiver_target"]
             type Target: ?Sized;
         }
 
-        impl<P: ?Sized, T: ?Sized> Receiver for P
+        impl<P: PointeeSized, T: PointeeSized> Receiver for P
         where
             P: Deref<Target = T>,
         {
@@ -686,7 +733,7 @@ pub mod ops {
             #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
             impl<A: Tuple, F: ?Sized> const Fn<A> for &F
             where
-                F: ~const Fn<A>,
+                F: [const] Fn<A>,
             {
                 extern "rust-call" fn call(&self, args: A) -> F::Output {
                     (**self).call(args)
@@ -697,7 +744,7 @@ pub mod ops {
             #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
             impl<A: Tuple, F: ?Sized> const FnMut<A> for &F
             where
-                F: ~const Fn<A>,
+                F: [const] Fn<A>,
             {
                 extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
                     (**self).call(args)
@@ -708,7 +755,7 @@ pub mod ops {
             #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
             impl<A: Tuple, F: ?Sized> const FnOnce<A> for &F
             where
-                F: ~const Fn<A>,
+                F: [const] Fn<A>,
             {
                 type Output = F::Output;
 
@@ -721,7 +768,7 @@ pub mod ops {
             #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
             impl<A: Tuple, F: ?Sized> const FnMut<A> for &mut F
             where
-                F: ~const FnMut<A>,
+                F: [const] FnMut<A>,
             {
                 extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
                     (*self).call_mut(args)
@@ -732,7 +779,7 @@ pub mod ops {
             #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
             impl<A: Tuple, F: ?Sized> const FnOnce<A> for &mut F
             where
-                F: ~const FnMut<A>,
+                F: [const] FnMut<A>,
             {
                 type Output = F::Output;
                 extern "rust-call" fn call_once(self, args: A) -> F::Output {
@@ -1006,18 +1053,18 @@ pub mod ops {
 
     // region:dispatch_from_dyn
     mod dispatch_from_dyn {
-        use crate::marker::Unsize;
+        use crate::marker::{PointeeSized, Unsize};
 
         #[lang = "dispatch_from_dyn"]
         pub trait DispatchFromDyn<T> {}
 
-        impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
+        impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<&'a U> for &'a T {}
 
-        impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
+        impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<&'a mut U> for &'a mut T {}
 
-        impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
+        impl<T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<*const U> for *const T {}
 
-        impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
+        impl<T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<*mut U> for *mut T {}
     }
     pub use self::dispatch_from_dyn::DispatchFromDyn;
     // endregion:dispatch_from_dyn
@@ -1025,15 +1072,17 @@ pub mod ops {
 
 // region:eq
 pub mod cmp {
+    use crate::marker::PointeeSized;
+
     #[lang = "eq"]
-    pub trait PartialEq<Rhs: ?Sized = Self> {
+    pub trait PartialEq<Rhs: PointeeSized = Self>: PointeeSized {
         fn eq(&self, other: &Rhs) -> bool;
         fn ne(&self, other: &Rhs) -> bool {
             !self.eq(other)
         }
     }
 
-    pub trait Eq: PartialEq<Self> {}
+    pub trait Eq: PartialEq<Self> + PointeeSized {}
 
     // region:derive
     #[rustc_builtin_macro]
@@ -1044,11 +1093,11 @@ pub mod cmp {
 
     // region:ord
     #[lang = "partial_ord"]
-    pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
+    pub trait PartialOrd<Rhs: PointeeSized = Self>: PartialEq<Rhs> + PointeeSized {
         fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>;
     }
 
-    pub trait Ord: Eq + PartialOrd<Self> {
+    pub trait Ord: Eq + PartialOrd<Self> + PointeeSized {
         fn cmp(&self, other: &Self) -> Ordering;
     }
 
@@ -1071,6 +1120,8 @@ pub mod cmp {
 
 // region:fmt
 pub mod fmt {
+    use crate::marker::PointeeSized;
+
     pub struct Error;
     pub type Result = crate::result::Result<(), Error>;
     pub struct Formatter<'a>;
@@ -1106,10 +1157,10 @@ pub mod fmt {
         }
     }
 
-    pub trait Debug {
+    pub trait Debug: PointeeSized {
         fn fmt(&self, f: &mut Formatter<'_>) -> Result;
     }
-    pub trait Display {
+    pub trait Display: PointeeSized {
         fn fmt(&self, f: &mut Formatter<'_>) -> Result;
     }
 
@@ -1238,8 +1289,11 @@ pub mod fmt {
     }
 
     // region:derive
-    #[rustc_builtin_macro]
-    pub macro Debug($item:item) {}
+    pub(crate) mod derive {
+        #[rustc_builtin_macro]
+        pub macro Debug($item:item) {}
+    }
+    pub use derive::Debug;
     // endregion:derive
 
     // region:builtin_impls
@@ -1268,7 +1322,7 @@ pub mod fmt {
         }
     }
 
-    impl<T: Debug + ?Sized> Debug for &T {
+    impl<T: Debug + PointeeSized> Debug for &T {
         fn fmt(&self, f: &mut Formatter<'_>) -> Result {
             (&**self).fmt(f)
         }
@@ -1512,6 +1566,8 @@ pub mod iter {
 
     mod traits {
         mod iterator {
+            use crate::marker::PointeeSized;
+
             #[doc(notable_trait)]
             #[lang = "iterator"]
             pub trait Iterator {
@@ -1543,7 +1599,7 @@ pub mod iter {
                 }
                 // endregion:iterators
             }
-            impl<I: Iterator + ?Sized> Iterator for &mut I {
+            impl<I: Iterator + PointeeSized> Iterator for &mut I {
                 type Item = I::Item;
                 fn next(&mut self) -> Option<I::Item> {
                     (**self).next()
@@ -1903,6 +1959,8 @@ pub mod prelude {
             panic,                                   // :panic
             result::Result::{self, Err, Ok},         // :result
             str::FromStr,                            // :str
+            fmt::derive::Debug,                      // :fmt, derive
+            hash::derive::Hash,                      // :hash, derive
         };
     }
 
diff --git a/src/tools/rust-analyzer/crates/toolchain/Cargo.toml b/src/tools/rust-analyzer/crates/toolchain/Cargo.toml
index 315a3a2890f..f561c1c0e2b 100644
--- a/src/tools/rust-analyzer/crates/toolchain/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/toolchain/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 home = "0.5.11"
diff --git a/src/tools/rust-analyzer/crates/tt/Cargo.toml b/src/tools/rust-analyzer/crates/tt/Cargo.toml
index 529fad3244a..82e7c24668f 100644
--- a/src/tools/rust-analyzer/crates/tt/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/tt/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 arrayvec.workspace = true
diff --git a/src/tools/rust-analyzer/crates/tt/src/iter.rs b/src/tools/rust-analyzer/crates/tt/src/iter.rs
index 0418c00174b..3246156f1cb 100644
--- a/src/tools/rust-analyzer/crates/tt/src/iter.rs
+++ b/src/tools/rust-analyzer/crates/tt/src/iter.rs
@@ -211,6 +211,7 @@ impl<'a, S: Copy> TtIter<'a, S> {
     }
 }
 
+#[derive(Clone)]
 pub enum TtElement<'a, S> {
     Leaf(&'a Leaf<S>),
     Subtree(&'a Subtree<S>, TtIter<'a, S>),
diff --git a/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml b/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml
index 9b32ee17abc..bd6c8331e66 100644
--- a/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 tracing.workspace = true
diff --git a/src/tools/rust-analyzer/crates/vfs/Cargo.toml b/src/tools/rust-analyzer/crates/vfs/Cargo.toml
index 546195481c6..e8a6195036e 100644
--- a/src/tools/rust-analyzer/crates/vfs/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/vfs/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 rust-version.workspace = true
 
 [lib]
+doctest = false
 
 [dependencies]
 rustc-hash.workspace = true
diff --git a/src/tools/rust-analyzer/crates/vfs/src/file_set.rs b/src/tools/rust-analyzer/crates/vfs/src/file_set.rs
index 1228e2e1774..0c41ede5b53 100644
--- a/src/tools/rust-analyzer/crates/vfs/src/file_set.rs
+++ b/src/tools/rust-analyzer/crates/vfs/src/file_set.rs
@@ -5,8 +5,8 @@
 use std::fmt;
 
 use fst::{IntoStreamer, Streamer};
-use nohash_hasher::IntMap;
-use rustc_hash::FxHashMap;
+use indexmap::IndexMap;
+use rustc_hash::{FxBuildHasher, FxHashMap};
 
 use crate::{AnchoredPath, FileId, Vfs, VfsPath};
 
@@ -14,7 +14,7 @@ use crate::{AnchoredPath, FileId, Vfs, VfsPath};
 #[derive(Default, Clone, Eq, PartialEq)]
 pub struct FileSet {
     files: FxHashMap<VfsPath, FileId>,
-    paths: IntMap<FileId, VfsPath>,
+    paths: IndexMap<FileId, VfsPath, FxBuildHasher>,
 }
 
 impl FileSet {
diff --git a/src/tools/rust-analyzer/docs/book/src/SUMMARY.md b/src/tools/rust-analyzer/docs/book/src/SUMMARY.md
index 1f211a97d78..dffdae94a6e 100644
--- a/src/tools/rust-analyzer/docs/book/src/SUMMARY.md
+++ b/src/tools/rust-analyzer/docs/book/src/SUMMARY.md
@@ -6,6 +6,7 @@
   - [rust-analyzer Binary](rust_analyzer_binary.md)
   - [Other Editors](other_editors.md)
 - [Troubleshooting](troubleshooting.md)
+  - [FAQ](faq.md)
 - [Configuration](configuration.md)
   - [Non-Cargo Based Projects](non_cargo_based_projects.md)
 - [Security](security.md)
diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
index 9404b1454a0..ebac26e1d60 100644
--- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
+++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
@@ -612,6 +612,13 @@ Default: `"client"`
 Controls file watching implementation.
 
 
+## rust-analyzer.highlightRelated.branchExitPoints.enable {#highlightRelated.branchExitPoints.enable}
+
+Default: `true`
+
+Enables highlighting of related return values while the cursor is on any `match`, `if`, or match arm arrow (`=>`).
+
+
 ## rust-analyzer.highlightRelated.breakPoints.enable {#highlightRelated.breakPoints.enable}
 
 Default: `true`
diff --git a/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md b/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md
index 1ada1cb24c2..8c06f33a9f7 100644
--- a/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md
+++ b/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md
@@ -694,24 +694,6 @@ interface CancelFlycheckParams {}
 
 Cancels all running flycheck processes.
 
-## Syntax Tree
-
-**Method:** `rust-analyzer/syntaxTree`
-
-**Request:**
-
-```typescript
-interface SyntaxTreeParams {
-    textDocument: TextDocumentIdentifier,
-    range?: Range,
-}
-```
-
-**Response:** `string`
-
-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`
diff --git a/src/tools/rust-analyzer/docs/book/src/faq.md b/src/tools/rust-analyzer/docs/book/src/faq.md
new file mode 100644
index 00000000000..c8720330901
--- /dev/null
+++ b/src/tools/rust-analyzer/docs/book/src/faq.md
@@ -0,0 +1,7 @@
+# Troubleshooting FAQ
+
+### I see a warning "Variable `None` should have snake_case name, e.g. `none`"
+
+rust-analyzer fails to resolve `None`, and thinks you are binding to a variable
+named `None`. That's usually a sign of a corrupted sysroot. Try removing and re-installing
+it: `rustup component remove rust-src` then `rustup component install rust-src`.
diff --git a/src/tools/rust-analyzer/docs/book/src/non_cargo_based_projects.md b/src/tools/rust-analyzer/docs/book/src/non_cargo_based_projects.md
index bbdb48bbbc9..befb631ec03 100644
--- a/src/tools/rust-analyzer/docs/book/src/non_cargo_based_projects.md
+++ b/src/tools/rust-analyzer/docs/book/src/non_cargo_based_projects.md
@@ -40,6 +40,9 @@ interface ProjectJson {
     /// several different "sysroots" in one graph of
     /// crates.
     sysroot_src?: string;
+    /// A ProjectJson describing the crates of the sysroot.
+    sysroot_project?: ProjectJson;
+
     /// List of groups of common cfg values, to allow
     /// sharing them between crates.
     ///
diff --git a/src/tools/rust-analyzer/docs/book/src/troubleshooting.md b/src/tools/rust-analyzer/docs/book/src/troubleshooting.md
index 1b2841421a4..a357cbef415 100644
--- a/src/tools/rust-analyzer/docs/book/src/troubleshooting.md
+++ b/src/tools/rust-analyzer/docs/book/src/troubleshooting.md
@@ -1,5 +1,8 @@
 # Troubleshooting
 
+First, search the [troubleshooting FAQ](faq.html). If your problem appears
+there (and the proposed solution works for you), great! Otherwise, read on.
+
 Start with looking at the rust-analyzer version. Try **rust-analyzer:
 Show RA Version** in VS Code (using **Command Palette** feature
 typically activated by Ctrl+Shift+P) or `rust-analyzer --version` in the
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index 26a21c1468d..3cb4c21ee1f 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -1532,6 +1532,16 @@
             {
                 "title": "highlightRelated",
                 "properties": {
+                    "rust-analyzer.highlightRelated.branchExitPoints.enable": {
+                        "markdownDescription": "Enables highlighting of related return values while the cursor is on any `match`, `if`, or match arm arrow (`=>`).",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "highlightRelated",
+                "properties": {
                     "rust-analyzer.highlightRelated.breakPoints.enable": {
                         "markdownDescription": "Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.",
                         "default": true,
diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts
index cdeea7333a6..073ff2f4703 100644
--- a/src/tools/rust-analyzer/editors/code/src/client.ts
+++ b/src/tools/rust-analyzer/editors/code/src/client.ts
@@ -3,7 +3,7 @@ import * as lc from "vscode-languageclient/node";
 import * as vscode from "vscode";
 import * as ra from "../src/lsp_ext";
 import * as Is from "vscode-languageclient/lib/common/utils/is";
-import { assert, unwrapUndefinable } from "./util";
+import { assert } from "./util";
 import * as diagnostics from "./diagnostics";
 import { WorkspaceEdit } from "vscode";
 import { type Config, prepareVSCodeConfig } from "./config";
@@ -188,11 +188,17 @@ export async function createClient(
                 context: await client.code2ProtocolConverter.asCodeActionContext(context, token),
             };
             const callback = async (
-                values: (lc.Command | lc.CodeAction)[] | null,
+                values: (lc.Command | lc.CodeAction | object)[] | null,
             ): Promise<(vscode.Command | vscode.CodeAction)[] | undefined> => {
                 if (values === null) return undefined;
                 const result: (vscode.CodeAction | vscode.Command)[] = [];
-                const groups = new Map<string, { index: number; items: vscode.CodeAction[] }>();
+                const groups = new Map<
+                    string,
+                    {
+                        primary: vscode.CodeAction;
+                        items: { label: string; arguments: lc.CodeAction }[];
+                    }
+                >();
                 for (const item of values) {
                     // In our case we expect to get code edits only from diagnostics
                     if (lc.CodeAction.is(item)) {
@@ -204,62 +210,55 @@ export async function createClient(
                         result.push(action);
                         continue;
                     }
-                    assert(
-                        isCodeActionWithoutEditsAndCommands(item),
-                        "We don't expect edits or commands here",
-                    );
-                    // eslint-disable-next-line @typescript-eslint/no-explicit-any
-                    const kind = client.protocol2CodeConverter.asCodeActionKind((item as any).kind);
-                    const action = new vscode.CodeAction(item.title, kind);
-                    // eslint-disable-next-line @typescript-eslint/no-explicit-any
-                    const group = (item as any).group;
-                    action.command = {
-                        command: "rust-analyzer.resolveCodeAction",
-                        title: item.title,
-                        arguments: [item],
-                    };
+                    assertIsCodeActionWithoutEditsAndCommands(item);
+                    const kind = client.protocol2CodeConverter.asCodeActionKind(item.kind);
+                    const group = item.group;
 
-                    // Set a dummy edit, so that VS Code doesn't try to resolve this.
-                    action.edit = new WorkspaceEdit();
+                    const mkAction = () => {
+                        const action = new vscode.CodeAction(item.title, kind);
+                        action.command = {
+                            command: "rust-analyzer.resolveCodeAction",
+                            title: item.title,
+                            arguments: [item],
+                        };
+                        // Set a dummy edit, so that VS Code doesn't try to resolve this.
+                        action.edit = new WorkspaceEdit();
+                        return action;
+                    };
 
                     if (group) {
                         let entry = groups.get(group);
                         if (!entry) {
-                            entry = { index: result.length, items: [] };
+                            entry = { primary: mkAction(), items: [] };
                             groups.set(group, entry);
-                            result.push(action);
+                        } else {
+                            entry.items.push({
+                                label: item.title,
+                                arguments: item,
+                            });
                         }
-                        entry.items.push(action);
                     } else {
-                        result.push(action);
+                        result.push(mkAction());
                     }
                 }
-                for (const [group, { index, items }] of groups) {
-                    if (items.length === 1) {
-                        const item = unwrapUndefinable(items[0]);
-                        result[index] = item;
-                    } else {
-                        const action = new vscode.CodeAction(group);
-                        const item = unwrapUndefinable(items[0]);
-                        action.kind = item.kind;
-                        action.command = {
+                for (const [group, { items, primary }] of groups) {
+                    // This group contains more than one item, so rewrite it to be a group action
+                    if (items.length !== 0) {
+                        const args = [
+                            {
+                                label: primary.title,
+                                arguments: primary.command!.arguments![0],
+                            },
+                            ...items,
+                        ];
+                        primary.title = group;
+                        primary.command = {
                             command: "rust-analyzer.applyActionGroup",
                             title: "",
-                            arguments: [
-                                items.map((item) => {
-                                    return {
-                                        label: item.title,
-                                        arguments: item.command!.arguments![0],
-                                    };
-                                }),
-                            ],
+                            arguments: [args],
                         };
-
-                        // Set a dummy edit, so that VS Code doesn't try to resolve this.
-                        action.edit = new WorkspaceEdit();
-
-                        result[index] = action;
                     }
+                    result.push(primary);
                 }
                 return result;
             };
@@ -363,17 +362,22 @@ class OverrideFeatures implements lc.StaticFeature {
     clear(): void {}
 }
 
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-function isCodeActionWithoutEditsAndCommands(value: any): boolean {
-    const candidate: lc.CodeAction = value;
-    return (
+function assertIsCodeActionWithoutEditsAndCommands(
+    // eslint-disable-next-line @typescript-eslint/no-explicit-any
+    candidate: any,
+): asserts candidate is lc.CodeAction & {
+    group?: string;
+} {
+    assert(
         candidate &&
-        Is.string(candidate.title) &&
-        (candidate.diagnostics === void 0 ||
-            Is.typedArray(candidate.diagnostics, lc.Diagnostic.is)) &&
-        (candidate.kind === void 0 || Is.string(candidate.kind)) &&
-        candidate.edit === void 0 &&
-        candidate.command === void 0
+            Is.string(candidate.title) &&
+            (candidate.diagnostics === undefined ||
+                Is.typedArray(candidate.diagnostics, lc.Diagnostic.is)) &&
+            (candidate.group === undefined || Is.string(candidate.group)) &&
+            (candidate.kind === undefined || Is.string(candidate.kind)) &&
+            candidate.edit === undefined &&
+            candidate.command === undefined,
+        `Expected a CodeAction without edits or commands, got: ${JSON.stringify(candidate)}`,
     );
 }
 
diff --git a/src/tools/rust-analyzer/editors/code/src/commands.ts b/src/tools/rust-analyzer/editors/code/src/commands.ts
index 3ac1a933d9e..25b30013fa1 100644
--- a/src/tools/rust-analyzer/editors/code/src/commands.ts
+++ b/src/tools/rust-analyzer/editors/code/src/commands.ts
@@ -1114,11 +1114,11 @@ export function applySnippetWorkspaceEditCommand(_ctx: CtxInit): Cmd {
     };
 }
 
-export function run(ctx: CtxInit): Cmd {
+export function run(ctx: CtxInit, mode?: "cursor"): Cmd {
     let prevRunnable: RunnableQuickPick | undefined;
 
     return async () => {
-        const item = await selectRunnable(ctx, prevRunnable);
+        const item = await selectRunnable(ctx, prevRunnable, false, true, mode);
         if (!item) return;
 
         item.detail = "rerun";
diff --git a/src/tools/rust-analyzer/editors/code/src/main.ts b/src/tools/rust-analyzer/editors/code/src/main.ts
index 5e500730693..996298524f1 100644
--- a/src/tools/rust-analyzer/editors/code/src/main.ts
+++ b/src/tools/rust-analyzer/editors/code/src/main.ts
@@ -167,7 +167,7 @@ function createCommands(): Record<string, CommandFactory> {
         viewCrateGraph: { enabled: commands.viewCrateGraph },
         viewFullCrateGraph: { enabled: commands.viewFullCrateGraph },
         expandMacro: { enabled: commands.expandMacro },
-        run: { enabled: commands.run },
+        run: { enabled: (ctx) => (mode?: "cursor") => commands.run(ctx, mode)() },
         copyRunCommandLine: { enabled: commands.copyRunCommandLine },
         debug: { enabled: commands.debug },
         newDebugConfig: { enabled: commands.newDebugConfig },
diff --git a/src/tools/rust-analyzer/editors/code/src/run.ts b/src/tools/rust-analyzer/editors/code/src/run.ts
index 40027cc7c85..95166c427b2 100644
--- a/src/tools/rust-analyzer/editors/code/src/run.ts
+++ b/src/tools/rust-analyzer/editors/code/src/run.ts
@@ -18,10 +18,15 @@ export async function selectRunnable(
     prevRunnable?: RunnableQuickPick,
     debuggeeOnly = false,
     showButtons: boolean = true,
+    mode?: "cursor",
 ): Promise<RunnableQuickPick | undefined> {
     const editor = ctx.activeRustEditor ?? ctx.activeCargoTomlEditor;
     if (!editor) return;
 
+    if (mode === "cursor") {
+        return selectRunnableAtCursor(ctx, editor, prevRunnable);
+    }
+
     // show a placeholder while we get the runnables from the server
     const quickPick = vscode.window.createQuickPick();
     quickPick.title = "Select Runnable";
@@ -54,6 +59,58 @@ export async function selectRunnable(
     );
 }
 
+async function selectRunnableAtCursor(
+    ctx: CtxInit,
+    editor: RustEditor,
+    prevRunnable?: RunnableQuickPick,
+): Promise<RunnableQuickPick | undefined> {
+    const runnableQuickPicks = await getRunnables(ctx.client, editor, prevRunnable, false);
+    let runnableQuickPickAtCursor = null;
+    const cursorPosition = ctx.client.code2ProtocolConverter.asPosition(editor.selection.active);
+    for (const runnableQuickPick of runnableQuickPicks) {
+        if (!runnableQuickPick.runnable.location?.targetRange) {
+            continue;
+        }
+        const runnableQuickPickRange = runnableQuickPick.runnable.location.targetRange;
+        if (
+            runnableQuickPickAtCursor?.runnable?.location?.targetRange != null &&
+            rangeContainsOtherRange(
+                runnableQuickPickRange,
+                runnableQuickPickAtCursor.runnable.location.targetRange,
+            )
+        ) {
+            continue;
+        }
+        if (rangeContainsPosition(runnableQuickPickRange, cursorPosition)) {
+            runnableQuickPickAtCursor = runnableQuickPick;
+        }
+    }
+    if (runnableQuickPickAtCursor == null) {
+        return;
+    }
+    return Promise.resolve(runnableQuickPickAtCursor);
+}
+
+function rangeContainsPosition(range: lc.Range, position: lc.Position): boolean {
+    return (
+        (position.line > range.start.line ||
+            (position.line === range.start.line && position.character >= range.start.character)) &&
+        (position.line < range.end.line ||
+            (position.line === range.end.line && position.character <= range.end.character))
+    );
+}
+
+function rangeContainsOtherRange(range: lc.Range, otherRange: lc.Range) {
+    return (
+        (range.start.line < otherRange.start.line ||
+            (range.start.line === otherRange.start.line &&
+                range.start.character <= otherRange.start.character)) &&
+        (range.end.line > otherRange.end.line ||
+            (range.end.line === otherRange.end.line &&
+                range.end.character >= otherRange.end.character))
+    );
+}
+
 export class RunnableQuickPick implements vscode.QuickPickItem {
     public label: string;
     public description?: string | undefined;
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index a454087b0cd..902793225ea 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-27733d46d79f4eb92e240fbba502c43022665735
+ad3b7257615c28aaf8212a189ec032b8af75de51
diff --git a/src/tools/rust-installer/README.md b/src/tools/rust-installer/README.md
index 99d8e5ca4cf..505ffe4093f 100644
--- a/src/tools/rust-installer/README.md
+++ b/src/tools/rust-installer/README.md
@@ -51,7 +51,7 @@ To combine installers.
 
 * Make install.sh not have to be customized, pull it's data from a
   config file.
-* Be more resiliant to installation failures, particularly if the disk
+* Be more resilient to installation failures, particularly if the disk
   is full.
 * Pre-install and post-uninstall scripts.
 * Allow components to depend on or contradict other components.
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index 7bf3bb195ee..050ddf47bae 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -81,7 +81,7 @@ version = "1.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9"
 dependencies = [
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -92,7 +92,7 @@ checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882"
 dependencies = [
  "anstyle",
  "once_cell_polyfill",
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -103,9 +103,9 @@ checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
 
 [[package]]
 name = "autocfg"
-version = "1.4.0"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
 
 [[package]]
 name = "bincode"
@@ -150,15 +150,15 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.18.1"
+version = "3.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
+checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
 
 [[package]]
 name = "cc"
-version = "1.2.27"
+version = "1.2.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc"
+checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362"
 dependencies = [
  "shlex",
 ]
@@ -459,12 +459,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
 
 [[package]]
 name = "errno"
-version = "0.3.12"
+version = "0.3.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
+checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
 dependencies = [
  "libc",
- "windows-sys",
+ "windows-sys 0.60.2",
 ]
 
 [[package]]
@@ -746,9 +746,9 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.9.0"
+version = "2.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
+checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
 dependencies = [
  "equivalent",
  "hashbrown",
@@ -863,9 +863,9 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
 
 [[package]]
 name = "markup5ever"
-version = "0.16.1"
+version = "0.16.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0a8096766c229e8c88a3900c9b44b7e06aa7f7343cc229158c3e58ef8f9973a"
+checksum = "2e4cd8c02f18a011991a039855480c64d74291c5792fcc160d55d77dc4de4a39"
 dependencies = [
  "log",
  "tendril",
@@ -991,7 +991,7 @@ version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c8911957c4b1549ac0dc74e30db9c8b0e66ddcd6d7acc33098f4c63a64a6d7ed"
 dependencies = [
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -1060,7 +1060,7 @@ checksum = "771b9704f8cd8b424ec747a320b30b47517a6966ba2c7da90047c16f4a962223"
 dependencies = [
  "bstr",
  "normpath",
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -1083,7 +1083,7 @@ dependencies = [
  "libc",
  "redox_syscall",
  "smallvec",
- "windows-targets",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -1100,9 +1100,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
 
 [[package]]
 name = "pest"
-version = "2.8.0"
+version = "2.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6"
+checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323"
 dependencies = [
  "memchr",
  "thiserror 2.0.12",
@@ -1111,9 +1111,9 @@ dependencies = [
 
 [[package]]
 name = "pest_derive"
-version = "2.8.0"
+version = "2.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5"
+checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc"
 dependencies = [
  "pest",
  "pest_generator",
@@ -1121,9 +1121,9 @@ dependencies = [
 
 [[package]]
 name = "pest_generator"
-version = "2.8.0"
+version = "2.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841"
+checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966"
 dependencies = [
  "pest",
  "pest_meta",
@@ -1134,11 +1134,10 @@ dependencies = [
 
 [[package]]
 name = "pest_meta"
-version = "2.8.0"
+version = "2.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0"
+checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5"
 dependencies = [
- "once_cell",
  "pest",
  "sha2",
 ]
@@ -1315,9 +1314,9 @@ dependencies = [
 
 [[package]]
 name = "r-efi"
-version = "5.2.0"
+version = "5.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
 
 [[package]]
 name = "railroad"
@@ -1403,7 +1402,7 @@ dependencies = [
  "errno",
  "libc",
  "linux-raw-sys",
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -1548,9 +1547,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
 
 [[package]]
 name = "syn"
-version = "2.0.103"
+version = "2.0.104"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8"
+checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1598,7 +1597,7 @@ dependencies = [
  "getrandom",
  "once_cell",
  "rustix",
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -1619,7 +1618,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed"
 dependencies = [
  "rustix",
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -1894,7 +1893,7 @@ version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
 dependencies = [
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -1962,7 +1961,16 @@ version = "0.59.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
 dependencies = [
- "windows-targets",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.60.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
+dependencies = [
+ "windows-targets 0.53.2",
 ]
 
 [[package]]
@@ -1971,14 +1979,30 @@ version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
 dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_gnullvm",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "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",
+ "windows_x86_64_msvc 0.52.6",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.53.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef"
+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]]
@@ -1988,48 +2012,96 @@ 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.52.6"
 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.52.6"
 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.52.6"
 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.52.6"
 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.52.6"
 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.52.6"
 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.7.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs
index addb0af4a54..6461f38f527 100644
--- a/src/tools/rustdoc-gui-test/src/main.rs
+++ b/src/tools/rustdoc-gui-test/src/main.rs
@@ -4,7 +4,7 @@ use std::sync::Arc;
 use std::{env, fs};
 
 use build_helper::util::try_run;
-use compiletest::header::TestProps;
+use compiletest::directives::TestProps;
 use config::Config;
 
 mod config;
diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js
index ff87b76aa45..9dc32f335a8 100644
--- a/src/tools/rustdoc-gui/tester.js
+++ b/src/tools/rustdoc-gui/tester.js
@@ -196,7 +196,7 @@ async function main(argv) {
         // This is more convenient that setting fields one by one.
         const args = [
             "--variable", "DOC_PATH", opts["doc_folder"].split("\\").join("/"),
-            "--enable-fail-on-js-error", "--allow-file-access-from-files",
+            "--allow-file-access-from-files",
         ];
         if (opts["debug"]) {
             debug = true;
diff --git a/src/tools/rustfmt/src/spanned.rs b/src/tools/rustfmt/src/spanned.rs
index 507647566d4..ac132999b62 100644
--- a/src/tools/rustfmt/src/spanned.rs
+++ b/src/tools/rustfmt/src/spanned.rs
@@ -122,7 +122,7 @@ impl Spanned for ast::GenericParam {
     fn span(&self) -> Span {
         let lo = match self.kind {
             _ if !self.attrs.is_empty() => self.attrs[0].span.lo(),
-            ast::GenericParamKind::Const { kw_span, .. } => kw_span.lo(),
+            ast::GenericParamKind::Const { span, .. } => span.lo(),
             _ => self.ident.span.lo(),
         };
         let hi = if self.bounds.is_empty() {
diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs
index 7ec1032dcb4..9ee10d86270 100644
--- a/src/tools/rustfmt/src/types.rs
+++ b/src/tools/rustfmt/src/types.rs
@@ -689,7 +689,7 @@ impl Rewrite for ast::GenericParam {
 
         let param_start = if let ast::GenericParamKind::Const {
             ref ty,
-            kw_span,
+            span,
             default,
         } = &self.kind
         {
@@ -711,7 +711,7 @@ impl Rewrite for ast::GenericParam {
                     default.rewrite_result(context, Shape::legacy(budget, shape.indent))?;
                 param.push_str(&rewrite);
             }
-            kw_span.lo()
+            span.lo()
         } else {
             param.push_str(rewrite_ident(context, self.ident));
             self.ident.span.lo()
@@ -835,12 +835,6 @@ impl Rewrite for ast::Ty {
                             .max_width_error(shape.width, self.span())?;
                         (shape, "dyn ")
                     }
-                    ast::TraitObjectSyntax::DynStar => {
-                        let shape = shape
-                            .offset_left(5)
-                            .max_width_error(shape.width, self.span())?;
-                        (shape, "dyn* ")
-                    }
                     ast::TraitObjectSyntax::None => (shape, ""),
                 };
                 let mut res = bounds.rewrite_result(context, shape)?;
@@ -1015,7 +1009,7 @@ impl Rewrite for ast::Ty {
                     })
                 }
             }
-            ast::TyKind::BareFn(ref bare_fn) => rewrite_bare_fn(bare_fn, self.span, context, shape),
+            ast::TyKind::FnPtr(ref fn_ptr) => rewrite_fn_ptr(fn_ptr, self.span, context, shape),
             ast::TyKind::Never => Ok(String::from("!")),
             ast::TyKind::MacCall(ref mac) => {
                 rewrite_macro(mac, context, shape, MacroPosition::Expression)
@@ -1111,8 +1105,8 @@ impl Rewrite for ast::TyPat {
     }
 }
 
-fn rewrite_bare_fn(
-    bare_fn: &ast::BareFnTy,
+fn rewrite_fn_ptr(
+    fn_ptr: &ast::FnPtrTy,
     span: Span,
     context: &RewriteContext<'_>,
     shape: Shape,
@@ -1121,7 +1115,7 @@ fn rewrite_bare_fn(
 
     let mut result = String::with_capacity(128);
 
-    if let Some(ref lifetime_str) = rewrite_bound_params(context, shape, &bare_fn.generic_params) {
+    if let Some(ref lifetime_str) = rewrite_bound_params(context, shape, &fn_ptr.generic_params) {
         result.push_str("for<");
         // 6 = "for<> ".len(), 4 = "for<".
         // This doesn't work out so nicely for multiline situation with lots of
@@ -1130,10 +1124,10 @@ fn rewrite_bare_fn(
         result.push_str("> ");
     }
 
-    result.push_str(crate::utils::format_safety(bare_fn.safety));
+    result.push_str(crate::utils::format_safety(fn_ptr.safety));
 
     result.push_str(&format_extern(
-        bare_fn.ext,
+        fn_ptr.ext,
         context.config.force_explicit_abi(),
     ));
 
@@ -1151,9 +1145,9 @@ fn rewrite_bare_fn(
     };
 
     let rewrite = format_function_type(
-        bare_fn.decl.inputs.iter(),
-        &bare_fn.decl.output,
-        bare_fn.decl.c_variadic(),
+        fn_ptr.decl.inputs.iter(),
+        &fn_ptr.decl.output,
+        fn_ptr.decl.c_variadic(),
         span,
         context,
         func_ty_shape,
diff --git a/src/tools/rustfmt/tests/source/let_chains.rs b/src/tools/rustfmt/tests/source/let_chains.rs
index 0c4d8aa85ea..fc2a9310569 100644
--- a/src/tools/rustfmt/tests/source/let_chains.rs
+++ b/src/tools/rustfmt/tests/source/let_chains.rs
@@ -1,3 +1,5 @@
+// rustfmt-edition: 2024
+
 fn main() {
     if let x = x && x {}
 
diff --git a/src/tools/rustfmt/tests/target/issue_5542.rs b/src/tools/rustfmt/tests/target/issue_5542.rs
deleted file mode 100644
index 730bb7b681a..00000000000
--- a/src/tools/rustfmt/tests/target/issue_5542.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-#![feature(dyn_star)]
-#![allow(incomplete_features)]
-
-use core::fmt::Debug;
-
-fn main() {
-    let i = 42;
-    let dyn_i = i as dyn* Debug;
-    dbg!(dyn_i);
-}
diff --git a/src/tools/rustfmt/tests/target/let_chains.rs b/src/tools/rustfmt/tests/target/let_chains.rs
index 204937b4cac..4fd6048d914 100644
--- a/src/tools/rustfmt/tests/target/let_chains.rs
+++ b/src/tools/rustfmt/tests/target/let_chains.rs
@@ -1,3 +1,5 @@
+// rustfmt-edition: 2024
+
 fn main() {
     if let x = x
         && x
diff --git a/src/tools/test-float-parse/src/lib.rs b/src/tools/test-float-parse/src/lib.rs
index f590149523b..0bd4878f9a6 100644
--- a/src/tools/test-float-parse/src/lib.rs
+++ b/src/tools/test-float-parse/src/lib.rs
@@ -119,7 +119,6 @@ pub fn register_tests(cfg: &Config) -> Vec<TestInfo> {
 
     // Register normal generators for all floats.
 
-    #[cfg(not(bootstrap))]
     #[cfg(target_has_reliable_f16)]
     register_float::<f16>(&mut tests, cfg);
     register_float::<f32>(&mut tests, cfg);
diff --git a/src/tools/test-float-parse/src/traits.rs b/src/tools/test-float-parse/src/traits.rs
index 16484f8fe2c..65a8721bfa5 100644
--- a/src/tools/test-float-parse/src/traits.rs
+++ b/src/tools/test-float-parse/src/traits.rs
@@ -170,7 +170,6 @@ macro_rules! impl_float {
 
 impl_float!(f32, u32; f64, u64);
 
-#[cfg(not(bootstrap))]
 #[cfg(target_has_reliable_f16)]
 impl_float!(f16, u16);
 
diff --git a/src/tools/test-float-parse/src/ui.rs b/src/tools/test-float-parse/src/ui.rs
index 73473eef0bf..1a9ba0dc1d9 100644
--- a/src/tools/test-float-parse/src/ui.rs
+++ b/src/tools/test-float-parse/src/ui.rs
@@ -118,7 +118,7 @@ pub fn finish_all(tests: &[TestInfo], total_elapsed: Duration, cfg: &Config) ->
         match result {
             Ok(FinishedAll) => (),
             Err(EarlyExit::Timeout) => {
-                println!("      exited early; exceded {:?} timeout", cfg.timeout)
+                println!("      exited early; exceeded {:?} timeout", cfg.timeout)
             }
             Err(EarlyExit::MaxFailures) => {
                 println!("      exited early; exceeded {:?} max failures", cfg.max_failures)
diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs
index 4f9a20fa9e2..d2da63a9703 100644
--- a/src/tools/tidy/src/ext_tool_checks.rs
+++ b/src/tools/tidy/src/ext_tool_checks.rs
@@ -65,6 +65,13 @@ fn check_impl(
         None => vec![],
     };
 
+    if lint_args.contains(&"spellcheck:fix") {
+        return Err(Error::Generic(
+            "`spellcheck:fix` is no longer valid, use `--extra=check=spellcheck --bless`"
+                .to_string(),
+        ));
+    }
+
     let python_all = lint_args.contains(&"py");
     let python_lint = lint_args.contains(&"py:lint") || python_all;
     let python_fmt = lint_args.contains(&"py:fmt") || python_all;
@@ -72,6 +79,7 @@ fn check_impl(
     let shell_lint = lint_args.contains(&"shell:lint") || shell_all;
     let cpp_all = lint_args.contains(&"cpp");
     let cpp_fmt = lint_args.contains(&"cpp:fmt") || cpp_all;
+    let spellcheck = lint_args.contains(&"spellcheck");
 
     let mut py_path = None;
 
@@ -224,6 +232,27 @@ fn check_impl(
         shellcheck_runner(&merge_args(&cfg_args, &file_args_shc))?;
     }
 
+    if spellcheck {
+        let config_path = root_path.join("typos.toml");
+        // sync target files with .github/workflows/spellcheck.yml
+        let mut args = vec![
+            "-c",
+            config_path.as_os_str().to_str().unwrap(),
+            "./compiler",
+            "./library",
+            "./src/bootstrap",
+            "./src/librustdoc",
+        ];
+
+        if bless {
+            eprintln!("spellcheck files and fix");
+            args.push("--write-changes");
+        } else {
+            eprintln!("spellcheck files");
+        }
+        spellcheck_runner(&args)?;
+    }
+
     Ok(())
 }
 
@@ -491,6 +520,36 @@ fn shellcheck_runner(args: &[&OsStr]) -> Result<(), Error> {
     if status.success() { Ok(()) } else { Err(Error::FailedCheck("shellcheck")) }
 }
 
+/// Check that spellchecker is installed then run it at the given path
+fn spellcheck_runner(args: &[&str]) -> Result<(), Error> {
+    // sync version with .github/workflows/spellcheck.yml
+    let expected_version = "typos-cli 1.34.0";
+    match Command::new("typos").arg("--version").output() {
+        Ok(o) => {
+            let stdout = String::from_utf8_lossy(&o.stdout);
+            if stdout.trim() != expected_version {
+                return Err(Error::Version {
+                    program: "typos",
+                    required: expected_version,
+                    installed: stdout.trim().to_string(),
+                });
+            }
+        }
+        Err(e) if e.kind() == io::ErrorKind::NotFound => {
+            return Err(Error::MissingReq(
+                "typos",
+                "spellcheck file checks",
+                // sync version with .github/workflows/spellcheck.yml
+                Some("install tool via `cargo install typos-cli@1.34.0`".to_owned()),
+            ));
+        }
+        Err(e) => return Err(e.into()),
+    }
+
+    let status = Command::new("typos").args(args).status()?;
+    if status.success() { Ok(()) } else { Err(Error::FailedCheck("typos")) }
+}
+
 /// Check git for tracked files matching an extension
 fn find_with_extension(
     root_path: &Path,
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index 7e27e0258c2..cac4dba2b49 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -276,7 +276,6 @@ ui/auto-traits/issue-23080-2.rs
 ui/auto-traits/issue-23080.rs
 ui/auto-traits/issue-83857-ub.rs
 ui/auto-traits/issue-84075.rs
-ui/auxiliary/issue-16822.rs
 ui/bench/issue-32062.rs
 ui/binding/issue-40402-1.rs
 ui/binding/issue-40402-2.rs
@@ -930,7 +929,6 @@ ui/dst/issue-90528-unsizing-suggestion-3.rs
 ui/dst/issue-90528-unsizing-suggestion-4.rs
 ui/dyn-keyword/issue-5153.rs
 ui/dyn-keyword/issue-56327-dyn-trait-in-macro-is-okay.rs
-ui/dyn-star/issue-102430.rs
 ui/empty/issue-37026.rs
 ui/entry-point/issue-118772.rs
 ui/enum-discriminant/auxiliary/issue-41394.rs
@@ -1368,10 +1366,6 @@ ui/infinite/issue-41731-infinite-macro-println.rs
 ui/intrinsics/issue-28575.rs
 ui/intrinsics/issue-84297-reifying-copy.rs
 ui/invalid/issue-114435-layout-type-err.rs
-ui/issue-11881.rs
-ui/issue-15924.rs
-ui/issue-16822.rs
-ui/issues-71798.rs
 ui/issues/auxiliary/issue-11224.rs
 ui/issues/auxiliary/issue-11508.rs
 ui/issues/auxiliary/issue-11529.rs
@@ -2847,7 +2841,6 @@ ui/macros/issue-98466.rs
 ui/macros/issue-99261.rs
 ui/macros/issue-99265.rs
 ui/macros/issue-99907.rs
-ui/macros/rfc-3086-metavar-expr/issue-111904.rs
 ui/malformed/issue-107423-unused-delim-only-one-no-pair.rs
 ui/malformed/issue-69341-malformed-derive-inert.rs
 ui/marker_trait_attr/issue-61651-type-mismatch.rs
diff --git a/src/tools/tidy/src/rustdoc_js.rs b/src/tools/tidy/src/rustdoc_js.rs
index 720f0712ee0..5e924544f0d 100644
--- a/src/tools/tidy/src/rustdoc_js.rs
+++ b/src/tools/tidy/src/rustdoc_js.rs
@@ -52,8 +52,7 @@ fn get_eslint_version() -> Option<String> {
 }
 
 pub fn check(librustdoc_path: &Path, tools_path: &Path, src_path: &Path, bad: &mut bool) {
-    let eslint_version_path =
-        src_path.join("ci/docker/host-x86_64/mingw-check-tidy/eslint.version");
+    let eslint_version_path = src_path.join("ci/docker/host-x86_64/tidy/eslint.version");
     let eslint_version = match std::fs::read_to_string(&eslint_version_path) {
         Ok(version) => version.trim().to_string(),
         Err(error) => {