about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/bootstrap.py2
-rw-r--r--src/bootstrap/defaults/bootstrap.dist.toml4
-rw-r--r--src/bootstrap/mk/Makefile.in8
-rw-r--r--src/bootstrap/src/core/build_steps/check.rs69
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs4
-rw-r--r--src/bootstrap/src/core/build_steps/format.rs37
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs6
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs43
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs26
-rw-r--r--src/bootstrap/src/core/builder/cargo.rs6
-rw-r--r--src/bootstrap/src/core/builder/mod.rs15
-rw-r--r--src/bootstrap/src/core/config/config.rs48
-rw-r--r--src/bootstrap/src/core/download.rs2
-rw-r--r--src/bootstrap/src/core/sanity.rs2
-rw-r--r--src/bootstrap/src/lib.rs4
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/bootstrap/src/utils/helpers.rs20
-rw-r--r--src/bootstrap/src/utils/proc_macro_deps.rs4
-rw-r--r--src/build_helper/src/git.rs6
-rw-r--r--src/ci/citool/Cargo.lock4
-rw-r--r--src/ci/citool/src/analysis.rs62
-rw-r--r--src/ci/citool/src/github.rs109
-rw-r--r--src/ci/citool/src/main.rs11
-rw-r--r--src/ci/citool/tests/test-jobs.yml2
-rw-r--r--src/ci/docker/README.md8
-rw-r--r--src/ci/docker/host-x86_64/mingw-check/Dockerfile3
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile1
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile (renamed from src/ci/docker/host-x86_64/x86_64-gnu-llvm-18/Dockerfile)8
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile1
-rwxr-xr-xsrc/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh1
-rw-r--r--src/ci/github-actions/jobs.yml86
m---------src/doc/book0
m---------src/doc/edition-guide0
m---------src/doc/nomicon0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
-rw-r--r--src/doc/rustc-dev-guide/.github/workflows/ci.yml1
-rw-r--r--src/doc/rustc-dev-guide/book.toml6
-rw-r--r--src/doc/rustc-dev-guide/ci/date-check/src/main.rs155
-rw-r--r--src/doc/rustc-dev-guide/examples/rustc-driver-example.rs16
-rw-r--r--src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs10
-rw-r--r--src/doc/rustc-dev-guide/examples/rustc-interface-example.rs13
-rw-r--r--src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs8
-rw-r--r--src/doc/rustc-dev-guide/rust-version2
-rw-r--r--src/doc/rustc-dev-guide/rustfmt.toml7
-rw-r--r--src/doc/rustc-dev-guide/src/SUMMARY.md18
-rw-r--r--src/doc/rustc-dev-guide/src/appendix/code-index.md2
-rw-r--r--src/doc/rustc-dev-guide/src/appendix/glossary.md1
-rw-r--r--src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md2
-rw-r--r--src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md2
-rw-r--r--src/doc/rustc-dev-guide/src/building/optimized-build.md9
-rw-r--r--src/doc/rustc-dev-guide/src/building/prerequisites.md2
-rw-r--r--src/doc/rustc-dev-guide/src/compiler-debugging.md3
-rw-r--r--src/doc/rustc-dev-guide/src/const-eval.md2
-rw-r--r--src/doc/rustc-dev-guide/src/diagnostics.md3
-rw-r--r--src/doc/rustc-dev-guide/src/hir.md43
-rw-r--r--src/doc/rustc-dev-guide/src/name-resolution.md6
-rw-r--r--src/doc/rustc-dev-guide/src/notification-groups/fuchsia.md12
-rw-r--r--src/doc/rustc-dev-guide/src/param_env/param_env_acquisition.md43
-rw-r--r--src/doc/rustc-dev-guide/src/param_env/param_env_construction_internals.md83
-rw-r--r--src/doc/rustc-dev-guide/src/param_env/param_env_summary.md18
-rw-r--r--src/doc/rustc-dev-guide/src/param_env/param_env_what_is_it.md59
-rw-r--r--src/doc/rustc-dev-guide/src/rustc-driver/getting-diagnostics.md3
-rw-r--r--src/doc/rustc-dev-guide/src/rustc-driver/remarks-on-perma-unstable-features.md54
-rw-r--r--src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md112
-rw-r--r--src/doc/rustc-dev-guide/src/rustdoc.md20
-rw-r--r--src/doc/rustc-dev-guide/src/solve/opaque-types.md2
-rw-r--r--src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_clif.md3
-rw-r--r--src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md3
-rw-r--r--src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/intro.md13
-rw-r--r--src/doc/rustc-dev-guide/src/tests/directives.md27
-rw-r--r--src/doc/rustc-dev-guide/src/tests/ecosystem-test-jobs/fuchsia.md (renamed from src/doc/rustc-dev-guide/src/tests/fuchsia.md)11
-rw-r--r--src/doc/rustc-dev-guide/src/tests/ecosystem-test-jobs/rust-for-linux.md (renamed from src/doc/rustc-dev-guide/src/tests/rust-for-linux.md)42
-rw-r--r--src/doc/rustc-dev-guide/src/tests/ecosystem.md4
-rw-r--r--src/doc/rustc-dev-guide/src/tests/intro.md8
-rw-r--r--src/doc/rustc-dev-guide/src/tests/ui.md62
-rw-r--r--src/doc/rustc-dev-guide/src/traits/caching.md2
-rw-r--r--src/doc/rustc-dev-guide/src/traits/resolution.md2
-rw-r--r--src/doc/rustc-dev-guide/src/ty_module/binders.md2
-rw-r--r--src/doc/rustc-dev-guide/src/typing_parameter_envs.md206
-rw-r--r--src/doc/rustc/src/SUMMARY.md4
-rw-r--r--src/doc/rustc/src/codegen-options/index.md13
-rw-r--r--src/doc/rustc/src/platform-support.md11
-rw-r--r--src/doc/rustc/src/platform-support/lynxos178.md77
-rw-r--r--src/doc/rustc/src/platform-support/windows-gnu.md32
-rw-r--r--src/doc/rustc/src/platform-support/windows-gnullvm.md (renamed from src/doc/rustc/src/platform-support/pc-windows-gnullvm.md)8
-rw-r--r--src/doc/style-guide/src/expressions.md78
-rw-r--r--src/doc/unstable-book/src/compiler-flags/dwarf-version.md13
-rw-r--r--src/doc/unstable-book/src/language-features/import-trait-associated-functions.md22
-rw-r--r--src/doc/unstable-book/src/language-features/intrinsics.md31
-rw-r--r--src/doc/unstable-book/src/language-features/offset-of-enum.md2
-rw-r--r--src/doc/unstable-book/src/language-features/type-alias-impl-trait.md159
-rw-r--r--src/librustdoc/Cargo.toml2
-rw-r--r--src/librustdoc/askama.toml (renamed from src/librustdoc/rinja.toml)0
-rw-r--r--src/librustdoc/clean/auto_trait.rs4
-rw-r--r--src/librustdoc/clean/inline.rs16
-rw-r--r--src/librustdoc/clean/mod.rs48
-rw-r--r--src/librustdoc/clean/types.rs7
-rw-r--r--src/librustdoc/clean/utils.rs1
-rw-r--r--src/librustdoc/core.rs1
-rw-r--r--src/librustdoc/doctest.rs1
-rw-r--r--src/librustdoc/doctest/runner.rs9
-rw-r--r--src/librustdoc/html/format.rs55
-rw-r--r--src/librustdoc/html/layout.rs2
-rw-r--r--src/librustdoc/html/markdown.rs2
-rw-r--r--src/librustdoc/html/render/context.rs12
-rw-r--r--src/librustdoc/html/render/mod.rs427
-rw-r--r--src/librustdoc/html/render/print_item.rs10
-rw-r--r--src/librustdoc/html/render/sidebar.rs6
-rw-r--r--src/librustdoc/html/render/tests.rs3
-rw-r--r--src/librustdoc/html/render/type_layout.rs2
-rw-r--r--src/librustdoc/html/sources.rs2
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css3
-rw-r--r--src/librustdoc/html/static/js/main.js5
-rw-r--r--src/librustdoc/html/static/js/rustdoc.d.ts14
-rw-r--r--src/librustdoc/html/static/js/settings.js127
-rw-r--r--src/librustdoc/html/templates/STYLE.md16
-rw-r--r--src/librustdoc/passes/calculate_doc_coverage.rs7
-rw-r--r--src/librustdoc/passes/check_doc_test_visibility.rs6
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs4
-rw-r--r--src/librustdoc/passes/strip_hidden.rs22
-rw-r--r--src/stage0922
-rw-r--r--src/tools/bump-stage0/src/main.rs25
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/Cargo.toml1
-rw-r--r--src/tools/clippy/clippy_lints/src/assigning_clones.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/booleans.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/duplicate_mod.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/equatable_if_let.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/format_args.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/format_push_string.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/utils.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/macro_use.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/single_match.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_trait_methods.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/module_style.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/mod.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/raw_strings.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/same_name_method.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs28
-rw-r--r--src/tools/clippy/clippy_lints/src/swap.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unconditional_recursion.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_self.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils/mod.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs18
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs22
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/sym.rs23
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/mod.rs10
-rw-r--r--src/tools/clippy/src/driver.rs1
-rw-r--r--src/tools/compiletest/Cargo.toml20
-rw-r--r--src/tools/compiletest/src/common.rs116
-rw-r--r--src/tools/compiletest/src/compute_diff.rs17
-rw-r--r--src/tools/compiletest/src/debuggers.rs31
-rw-r--r--src/tools/compiletest/src/directive-list.rs2
-rw-r--r--src/tools/compiletest/src/errors.rs89
-rw-r--r--src/tools/compiletest/src/executor.rs293
-rw-r--r--src/tools/compiletest/src/executor/deadline.rs78
-rw-r--r--src/tools/compiletest/src/executor/json.rs111
-rw-r--r--src/tools/compiletest/src/executor/libtest.rs111
-rw-r--r--src/tools/compiletest/src/header.rs187
-rw-r--r--src/tools/compiletest/src/header/needs.rs48
-rw-r--r--src/tools/compiletest/src/header/tests.rs80
-rw-r--r--src/tools/compiletest/src/json.rs116
-rw-r--r--src/tools/compiletest/src/lib.rs281
-rw-r--r--src/tools/compiletest/src/raise_fd_limit.rs13
-rw-r--r--src/tools/compiletest/src/read2.rs28
-rw-r--r--src/tools/compiletest/src/runtest.rs285
-rw-r--r--src/tools/compiletest/src/runtest/assembly.rs4
-rw-r--r--src/tools/compiletest/src/runtest/codegen_units.rs4
-rw-r--r--src/tools/compiletest/src/runtest/coverage.rs21
-rw-r--r--src/tools/compiletest/src/runtest/debugger.rs19
-rw-r--r--src/tools/compiletest/src/runtest/debuginfo.rs56
-rw-r--r--src/tools/compiletest/src/runtest/js_doc.rs3
-rw-r--r--src/tools/compiletest/src/runtest/mir_opt.rs43
-rw-r--r--src/tools/compiletest/src/runtest/run_make.rs32
-rw-r--r--src/tools/compiletest/src/runtest/ui.rs10
-rw-r--r--src/tools/compiletest/src/tests.rs12
-rw-r--r--src/tools/compiletest/src/util.rs38
-rw-r--r--src/tools/compiletest/src/util/tests.rs10
-rw-r--r--src/tools/generate-copyright/Cargo.toml2
-rw-r--r--src/tools/generate-copyright/src/main.rs4
-rw-r--r--src/tools/generate-windows-sys/Cargo.toml2
-rw-r--r--src/tools/miri/Cargo.lock573
-rw-r--r--src/tools/miri/Cargo.toml9
-rw-r--r--src/tools/miri/README.md1
-rw-r--r--src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs5
-rw-r--r--src/tools/miri/cargo-miri/Cargo.lock253
-rw-r--r--src/tools/miri/cargo-miri/Cargo.toml4
-rwxr-xr-xsrc/tools/miri/ci/ci.sh6
-rw-r--r--src/tools/miri/miri-script/Cargo.lock330
-rw-r--r--src/tools/miri/miri-script/Cargo.toml6
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/bin/miri.rs2
-rw-r--r--src/tools/miri/src/clock.rs30
-rw-r--r--src/tools/miri/src/concurrency/thread.rs16
-rw-r--r--src/tools/miri/src/eval.rs10
-rw-r--r--src/tools/miri/src/helpers.rs3
-rw-r--r--src/tools/miri/src/intrinsics/mod.rs8
-rw-r--r--src/tools/miri/src/lib.rs2
-rw-r--r--src/tools/miri/src/machine.rs8
-rw-r--r--src/tools/miri/src/shims/files.rs115
-rw-r--r--src/tools/miri/src/shims/time.rs44
-rw-r--r--src/tools/miri/src/shims/unix/fd.rs6
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs2
-rw-r--r--src/tools/miri/src/shims/unix/freebsd/foreign_items.rs8
-rw-r--r--src/tools/miri/src/shims/unix/freebsd/mod.rs1
-rw-r--r--src/tools/miri/src/shims/unix/freebsd/sync.rs251
-rw-r--r--src/tools/miri/src/shims/unix/fs.rs94
-rw-r--r--src/tools/miri/src/shims/unix/linux_like/epoll.rs4
-rw-r--r--src/tools/miri/src/shims/unix/linux_like/eventfd.rs2
-rw-r--r--src/tools/miri/src/shims/unix/macos/foreign_items.rs3
-rw-r--r--src/tools/miri/src/shims/unix/unnamed_socket.rs2
-rw-r--r--src/tools/miri/src/shims/windows/foreign_items.rs229
-rw-r--r--src/tools/miri/src/shims/windows/fs.rs402
-rw-r--r--src/tools/miri/src/shims/windows/handle.rs84
-rw-r--r--src/tools/miri/src/shims/windows/mod.rs2
-rw-r--r--src/tools/miri/src/shims/windows/thread.rs8
-rw-r--r--src/tools/miri/test-cargo-miri/Cargo.lock18
-rw-r--r--src/tools/miri/test-cargo-miri/Cargo.toml2
-rwxr-xr-xsrc/tools/miri/test-cargo-miri/run-test.py36
-rw-r--r--src/tools/miri/test-cargo-miri/src/lib.rs3
-rw-r--r--src/tools/miri/test-cargo-miri/src/main.rs4
-rw-r--r--src/tools/miri/test-cargo-miri/subcrate/Cargo.toml4
-rw-r--r--src/tools/miri/test-cargo-miri/subcrate/src/lib.rs22
-rw-r--r--src/tools/miri/test-cargo-miri/test.empty.ref (renamed from src/tools/miri/test-cargo-miri/test.stderr-empty.ref)0
-rw-r--r--src/tools/miri/test-cargo-miri/test.proc-macro.stderr.ref (renamed from src/tools/miri/test-cargo-miri/test.stderr-proc-macro.ref)1
-rw-r--r--src/tools/miri/test-cargo-miri/test.stderr-proc-macro-doctest.ref1
-rw-r--r--src/tools/miri/test-cargo-miri/test.stdout-empty.ref0
-rw-r--r--src/tools/miri/test-cargo-miri/test.subcrate.cross-target.stdout.ref11
-rw-r--r--src/tools/miri/test-cargo-miri/test.subcrate.stdout.ref10
-rw-r--r--src/tools/miri/test_dependencies/Cargo.lock205
-rw-r--r--src/tools/miri/test_dependencies/Cargo.toml4
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs2
-rw-r--r--src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs260
-rw-r--r--src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs10
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs1
-rw-r--r--src/tools/miri/tests/pass-dep/shims/windows-fs.rs207
-rw-r--r--src/tools/miri/tests/pass/float.rs5
-rw-r--r--src/tools/miri/tests/pass/issues/issue-134713-swap_nonoverlapping_untyped.rs30
-rw-r--r--src/tools/miri/tests/pass/path.rs25
-rw-r--r--src/tools/miri/tests/pass/shims/fs.rs36
-rw-r--r--src/tools/miri/triagebot.toml6
-rw-r--r--src/tools/opt-dist/src/training.rs4
-rw-r--r--src/tools/run-make-support/src/artifact_names.rs53
-rw-r--r--src/tools/run-make-support/src/lib.rs1
-rw-r--r--src/tools/run-make-support/src/linker.rs36
-rw-r--r--src/tools/rust-analyzer/Cargo.lock9
-rw-r--r--src/tools/rust-analyzer/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs111
-rw-r--r--src/tools/rust-analyzer/crates/parser/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/lexed_str.rs10
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs29
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs22
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs2
-rw-r--r--src/tools/rust-analyzer/crates/syntax/Cargo.toml3
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs2
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/lib.rs9
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/validation.rs8
-rw-r--r--src/tools/rustbook/Cargo.lock161
m---------src/tools/rustc-perf0
-rw-r--r--src/tools/rustdoc-gui-test/Cargo.toml1
-rw-r--r--src/tools/rustdoc-gui-test/src/main.rs6
-rw-r--r--src/tools/rustfmt/src/expr.rs2
-rw-r--r--src/tools/rustfmt/src/items.rs6
-rw-r--r--src/tools/rustfmt/src/macros.rs14
-rw-r--r--src/tools/rustfmt/src/patterns.rs2
-rw-r--r--src/tools/tidy/src/deps.rs17
-rw-r--r--src/tools/tidy/src/unit_tests.rs51
-rw-r--r--src/tools/unicode-table-generator/src/range_search.rs71
-rw-r--r--src/tools/unicode-table-generator/src/skiplist.rs66
297 files changed, 6723 insertions, 3784 deletions
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 140f601253c..42ad14a81d0 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -1331,7 +1331,7 @@ def bootstrap(args):
     build.check_vendored_status()
 
     if not os.path.exists(build.build_dir):
-        os.makedirs(build.build_dir)
+        os.makedirs(os.path.realpath(build.build_dir))
 
     # Fetch/build the bootstrap
     build.download_toolchain()
diff --git a/src/bootstrap/defaults/bootstrap.dist.toml b/src/bootstrap/defaults/bootstrap.dist.toml
index 7b381b416ca..f0cb34eb458 100644
--- a/src/bootstrap/defaults/bootstrap.dist.toml
+++ b/src/bootstrap/defaults/bootstrap.dist.toml
@@ -7,6 +7,8 @@ test-stage = 2
 doc-stage = 2
 # When compiling from source, you usually want all tools.
 extended = true
+# Use libtest built from the source tree instead of the precompiled one from stage 0.
+compiletest-use-stage0-libtest = false
 
 # Most users installing from source want to build all parts of the project from source.
 [llvm]
@@ -15,7 +17,7 @@ download-ci-llvm = false
 [rust]
 # We have several defaults in bootstrap that depend on whether the channel is `dev` (e.g. `omit-git-hash` and `download-ci-llvm`).
 # Make sure they don't get set when installing from source.
-channel = "nightly"
+channel = "auto-detect"
 # Never download a rustc, distributions must build a fresh compiler.
 download-rustc = false
 lld = true
diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in
index 6cb0b19d763..08a288170fa 100644
--- a/src/bootstrap/mk/Makefile.in
+++ b/src/bootstrap/mk/Makefile.in
@@ -73,12 +73,12 @@ check-aux:
 		$(BOOTSTRAP) miri --stage 2 library/std \
 		$(BOOTSTRAP_ARGS) \
 		--no-doc -- \
-		--skip fs:: --skip net:: --skip process:: --skip sys::pal::
+		--skip fs:: --skip net:: --skip process:: --skip sys::fd:: --skip sys::pal::
 	$(Q)MIRIFLAGS="-Zmiri-disable-isolation" \
 		$(BOOTSTRAP) miri --stage 2 library/std \
 		$(BOOTSTRAP_ARGS) \
 		--doc -- \
-		--skip fs:: --skip net:: --skip process:: --skip sys::pal::
+		--skip fs:: --skip net:: --skip process:: --skip sys::fd:: --skip sys::pal::
 	# Also test some very target-specific modules on other targets
 	# (making sure to cover an i686 target as well).
 	$(Q)MIRIFLAGS="-Zmiri-disable-isolation" BOOTSTRAP_SKIP_TARGET_SANITY=1 \
@@ -120,10 +120,6 @@ ci-msvc: ci-msvc-py ci-msvc-ps1
 # Set of tests that should represent half of the time of the test suite.
 # Used to split tests across multiple CI runners.
 # Test both x and bootstrap entrypoints.
-ci-mingw-x-1:
-	$(Q)$(CFG_SRC_DIR)/x test --stage 2 $(SKIP_COMPILER) $(TEST_SET2)
-ci-mingw-x-2:
-	$(Q)$(CFG_SRC_DIR)/x test --stage 2 $(SKIP_SRC) $(TEST_SET2)
 ci-mingw-x:
 	$(Q)$(CFG_SRC_DIR)/x test --stage 2 $(TEST_SET1)
 ci-mingw-bootstrap:
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index e67bc62a603..ae9511b7867 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -3,7 +3,7 @@
 use crate::core::build_steps::compile::{
     add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make,
 };
-use crate::core::build_steps::tool::{SourceType, prepare_tool_cargo};
+use crate::core::build_steps::tool::{COMPILETEST_ALLOW_FEATURES, SourceType, prepare_tool_cargo};
 use crate::core::builder::{
     self, Alias, Builder, Kind, RunConfig, ShouldRun, Step, crate_description,
 };
@@ -369,6 +369,69 @@ impl Step for RustAnalyzer {
     }
 }
 
+/// Compiletest is implicitly "checked" when it gets built in order to run tests,
+/// so this is mainly for people working on compiletest to run locally.
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Compiletest {
+    pub target: TargetSelection,
+}
+
+impl Step for Compiletest {
+    type Output = ();
+    const ONLY_HOSTS: bool = true;
+    const DEFAULT: bool = false;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/tools/compiletest")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(Compiletest { target: run.target });
+    }
+
+    fn run(self, builder: &Builder<'_>) {
+        let mode = if builder.config.compiletest_use_stage0_libtest {
+            Mode::ToolBootstrap
+        } else {
+            Mode::ToolStd
+        };
+
+        let compiler = builder.compiler(
+            if mode == Mode::ToolBootstrap { 0 } else { builder.top_stage },
+            builder.config.build,
+        );
+
+        if mode != Mode::ToolBootstrap {
+            builder.ensure(Rustc::new(self.target, builder));
+        }
+
+        let mut cargo = prepare_tool_cargo(
+            builder,
+            compiler,
+            mode,
+            self.target,
+            builder.kind,
+            "src/tools/compiletest",
+            SourceType::InTree,
+            &[],
+        );
+
+        cargo.allow_features(COMPILETEST_ALLOW_FEATURES);
+
+        // For ./x.py clippy, don't run with --all-targets because
+        // linting tests and benchmarks can produce very noisy results
+        if builder.kind != Kind::Clippy {
+            cargo.arg("--all-targets");
+        }
+
+        let stamp = BuildStamp::new(&builder.cargo_out(compiler, mode, self.target))
+            .with_prefix("compiletest-check");
+
+        let _guard = builder.msg_check("compiletest artifacts", self.target);
+        run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
+    }
+}
+
 macro_rules! tool_check_step {
     (
         $name:ident {
@@ -464,7 +527,3 @@ tool_check_step!(Bootstrap { path: "src/bootstrap", default: false });
 // `run-make-support` will be built as part of suitable run-make compiletest test steps, but support
 // check to make it easier to work on.
 tool_check_step!(RunMakeSupport { path: "src/tools/run-make-support", default: false });
-
-// Compiletest is implicitly "checked" when it gets built in order to run tests,
-// so this is mainly for people working on compiletest to run locally.
-tool_check_step!(Compiletest { path: "src/tools/compiletest", default: false });
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 18b5d4426b1..dab58fccf5e 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -2398,7 +2398,9 @@ pub fn run_cargo(
     // Ok now we need to actually find all the files listed in `toplevel`. We've
     // got a list of prefix/extensions and we basically just need to find the
     // most recent file in the `deps` folder corresponding to each one.
-    let contents = t!(target_deps_dir.read_dir())
+    let contents = target_deps_dir
+        .read_dir()
+        .unwrap_or_else(|e| panic!("Couldn't read {}: {}", target_deps_dir.display(), e))
         .map(|e| t!(e))
         .map(|e| (e.path(), e.file_name().into_string().unwrap(), t!(e.metadata())))
         .collect::<Vec<_>>();
diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs
index b1a97bde97b..9da8b27a917 100644
--- a/src/bootstrap/src/core/build_steps/format.rs
+++ b/src/bootstrap/src/core/build_steps/format.rs
@@ -81,14 +81,19 @@ fn update_rustfmt_version(build: &Builder<'_>) {
     let Some((version, stamp_file)) = get_rustfmt_version(build) else {
         return;
     };
-    t!(std::fs::write(stamp_file.path(), version))
+
+    t!(stamp_file.add_stamp(version).write());
 }
 
-/// Returns the Rust files modified between the `merge-base` of HEAD and
-/// rust-lang/master and what is now on the disk. Does not include removed files.
+/// Returns the Rust files modified between the last merge commit and what is now on the disk.
+/// Does not include removed files.
 ///
 /// Returns `None` if all files should be formatted.
 fn get_modified_rs_files(build: &Builder<'_>) -> Result<Option<Vec<String>>, String> {
+    // In CI `get_git_modified_files` returns something different to normal environment.
+    // This shouldn't be called in CI anyway.
+    assert!(!build.config.is_running_on_ci);
+
     if !verify_rustfmt_version(build) {
         return Ok(None);
     }
@@ -103,7 +108,7 @@ struct RustfmtConfig {
 
 // Prints output describing a collection of paths, with lines such as "formatted modified file
 // foo/bar/baz" or "skipped 20 untracked files".
-fn print_paths(build: &Builder<'_>, verb: &str, adjective: Option<&str>, paths: &[String]) {
+fn print_paths(verb: &str, adjective: Option<&str>, paths: &[String]) {
     let len = paths.len();
     let adjective =
         if let Some(adjective) = adjective { format!("{adjective} ") } else { String::new() };
@@ -114,9 +119,6 @@ fn print_paths(build: &Builder<'_>, verb: &str, adjective: Option<&str>, paths:
     } else {
         println!("fmt: {verb} {len} {adjective}files");
     }
-    if len > 1000 && !build.config.is_running_on_ci {
-        println!("hint: if this number seems too high, try running `git fetch origin master`");
-    }
 }
 
 pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
@@ -189,7 +191,7 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
                 )
                 .map(|x| x.to_string())
                 .collect();
-            print_paths(build, "skipped", Some("untracked"), &untracked_paths);
+            print_paths("skipped", Some("untracked"), &untracked_paths);
 
             for untracked_path in untracked_paths {
                 // The leading `/` makes it an exact match against the
@@ -212,7 +214,13 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
                             override_builder.add(&format!("/{file}")).expect(&file);
                         }
                     }
-                    Ok(None) => {}
+                    Ok(None) => {
+                        // NOTE: `Ok(None)` signifies that we need to format all files.
+                        // The tricky part here is that if `override_builder` isn't given any white
+                        // list files (i.e. files to be formatted, added without leading `!`), it
+                        // will instead look for *all* files. So, by doing nothing here, we are
+                        // actually making it so we format all files.
+                    }
                     Err(err) => {
                         eprintln!("fmt warning: Something went wrong running git commands:");
                         eprintln!("fmt warning: {err}");
@@ -318,7 +326,7 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
     });
     let mut paths = formatted_paths.into_inner().unwrap();
     paths.sort();
-    print_paths(build, if check { "checked" } else { "formatted" }, adjective, &paths);
+    print_paths(if check { "checked" } else { "formatted" }, adjective, &paths);
 
     drop(tx);
 
@@ -328,7 +336,10 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
         crate::exit!(1);
     }
 
-    if !check {
-        update_rustfmt_version(build);
-    }
+    // Update `build/.rustfmt-stamp`, allowing this code to ignore files which have not been changed
+    // since last merge.
+    //
+    // NOTE: Because of the exit above, this is only reachable if formatting / format checking
+    // succeeded. So we are not commiting the version if formatting was not good.
+    update_rustfmt_version(build);
 }
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index e21804fa3c0..69a8bd59f16 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -346,8 +346,6 @@ impl Step for Llvm {
             .define("LLVM_INCLUDE_DOCS", "OFF")
             .define("LLVM_INCLUDE_BENCHMARKS", "OFF")
             .define("LLVM_INCLUDE_TESTS", enable_tests)
-            // FIXME: remove this when minimal llvm is 19
-            .define("LLVM_ENABLE_TERMINFO", "OFF")
             .define("LLVM_ENABLE_LIBEDIT", "OFF")
             .define("LLVM_ENABLE_BINDINGS", "OFF")
             .define("LLVM_ENABLE_Z3_SOLVER", "OFF")
@@ -610,11 +608,11 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) {
     let version = get_llvm_version(builder, llvm_config);
     let mut parts = version.split('.').take(2).filter_map(|s| s.parse::<u32>().ok());
     if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) {
-        if major >= 18 {
+        if major >= 19 {
             return;
         }
     }
-    panic!("\n\nbad LLVM version: {version}, need >=18\n\n")
+    panic!("\n\nbad LLVM version: {version}, need >=19\n\n")
 }
 
 fn configure_cmake(
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 81f6b473c45..b1a3bba0887 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -15,7 +15,7 @@ use crate::core::build_steps::doc::DocumentationFormat;
 use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags};
 use crate::core::build_steps::llvm::get_llvm_version;
 use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget;
-use crate::core::build_steps::tool::{self, SourceType, Tool};
+use crate::core::build_steps::tool::{self, COMPILETEST_ALLOW_FEATURES, SourceType, Tool};
 use crate::core::build_steps::toolstate::ToolState;
 use crate::core::build_steps::{compile, dist, llvm};
 use crate::core::builder::{
@@ -261,13 +261,7 @@ impl Step for Cargotest {
             .args(builder.config.test_args())
             .env("RUSTC", builder.rustc(compiler))
             .env("RUSTDOC", builder.rustdoc(compiler));
-        add_rustdoc_cargo_linker_args(
-            &mut cmd,
-            builder,
-            compiler.host,
-            LldThreads::No,
-            compiler.stage,
-        );
+        add_rustdoc_cargo_linker_args(&mut cmd, builder, compiler.host, LldThreads::No);
         cmd.delay_failure().run(builder);
     }
 }
@@ -727,7 +721,7 @@ impl Step for CompiletestTest {
             SourceType::InTree,
             &[],
         );
-        cargo.allow_features("test");
+        cargo.allow_features(COMPILETEST_ALLOW_FEATURES);
         run_cargo_test(cargo, &[], &[], "compiletest self test", host, builder);
     }
 }
@@ -845,7 +839,7 @@ impl Step for RustdocTheme {
             .env("CFG_RELEASE_CHANNEL", &builder.config.channel)
             .env("RUSTDOC_REAL", builder.rustdoc(self.compiler))
             .env("RUSTC_BOOTSTRAP", "1");
-        cmd.args(linker_args(builder, self.compiler.host, LldThreads::No, self.compiler.stage));
+        cmd.args(linker_args(builder, self.compiler.host, LldThreads::No));
 
         cmd.delay_failure().run(builder);
     }
@@ -1021,13 +1015,7 @@ impl Step for RustdocGUI {
         cmd.env("RUSTDOC", builder.rustdoc(self.compiler))
             .env("RUSTC", builder.rustc(self.compiler));
 
-        add_rustdoc_cargo_linker_args(
-            &mut cmd,
-            builder,
-            self.compiler.host,
-            LldThreads::No,
-            self.compiler.stage,
-        );
+        add_rustdoc_cargo_linker_args(&mut cmd, builder, self.compiler.host, LldThreads::No);
 
         for path in &builder.paths {
             if let Some(p) = helpers::is_valid_test_suite_arg(path, "tests/rustdoc-gui", builder) {
@@ -1624,9 +1612,6 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
             builder.tool_exe(Tool::RunMakeSupport);
         }
 
-        // Also provide `rust_test_helpers` for the host.
-        builder.ensure(TestHelpers { target: compiler.host });
-
         // ensure that `libproc_macro` is available on the host.
         if suite == "mir-opt" {
             builder.ensure(compile::Std::new(compiler, compiler.host).is_for_mir_opt_tests(true));
@@ -1634,11 +1619,6 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
             builder.ensure(compile::Std::new(compiler, compiler.host));
         }
 
-        // As well as the target
-        if suite != "mir-opt" {
-            builder.ensure(TestHelpers { target });
-        }
-
         let mut cmd = builder.tool_cmd(Tool::Compiletest);
 
         if suite == "mir-opt" {
@@ -1804,11 +1784,18 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
         }
 
         let mut hostflags = flags.clone();
-        hostflags.push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display()));
-        hostflags.extend(linker_flags(builder, compiler.host, LldThreads::No, compiler.stage));
+        hostflags.extend(linker_flags(builder, compiler.host, LldThreads::No));
 
         let mut targetflags = flags;
-        targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display()));
+
+        // Provide `rust_test_helpers` for both host and target.
+        if suite == "ui" || suite == "incremental" {
+            builder.ensure(TestHelpers { target: compiler.host });
+            builder.ensure(TestHelpers { target });
+            hostflags
+                .push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display()));
+            targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display()));
+        }
 
         for flag in hostflags {
             cmd.arg("--host-rustcflags").arg(flag);
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index cd57e06ae04..3426da51a80 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -148,10 +148,9 @@ impl Step for ToolBuild {
             &self.extra_features,
         );
 
-        if path.ends_with("/rustdoc") &&
-            // rustdoc is performance sensitive, so apply LTO to it.
-            is_lto_stage(&self.compiler)
-        {
+        // Rustc tools (miri, clippy, cargo, rustfmt, rust-analyzer)
+        // could use the additional optimizations.
+        if self.mode == Mode::ToolRustc && is_lto_stage(&self.compiler) {
             let lto = match builder.config.rust_lto {
                 RustcLto::Off => Some("off"),
                 RustcLto::Thin => Some("thin"),
@@ -425,11 +424,14 @@ macro_rules! bootstrap_tool {
                     }
                 )*
 
+                let is_unstable = false $(|| $unstable)*;
+                let compiletest_wants_stage0 = $tool_name == "compiletest" && builder.config.compiletest_use_stage0_libtest;
+
                 builder.ensure(ToolBuild {
                     compiler: self.compiler,
                     target: self.target,
                     tool: $tool_name,
-                    mode: if false $(|| $unstable)* {
+                    mode: if is_unstable && !compiletest_wants_stage0 {
                         // use in-tree libraries for unstable features
                         Mode::ToolStd
                     } else {
@@ -442,7 +444,11 @@ macro_rules! bootstrap_tool {
                         SourceType::InTree
                     },
                     extra_features: vec![],
-                    allow_features: concat!($($allow_features)*),
+                    allow_features: {
+                        let mut _value = "";
+                        $( _value = $allow_features; )?
+                        _value
+                    },
                     cargo_args: vec![],
                     artifact_kind: if false $(|| $artifact_kind == ToolArtifactKind::Library)* {
                         ToolArtifactKind::Library
@@ -456,6 +462,8 @@ macro_rules! bootstrap_tool {
     }
 }
 
+pub(crate) const COMPILETEST_ALLOW_FEATURES: &str = "test,internal_output_capture";
+
 bootstrap_tool!(
     // This is marked as an external tool because it includes dependencies
     // from submodules. Trying to keep the lints in sync between all the repos
@@ -466,7 +474,7 @@ bootstrap_tool!(
     Tidy, "src/tools/tidy", "tidy";
     Linkchecker, "src/tools/linkchecker", "linkchecker";
     CargoTest, "src/tools/cargotest", "cargotest";
-    Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true, allow_features = "test";
+    Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES;
     BuildManifest, "src/tools/build-manifest", "build-manifest";
     RemoteTestClient, "src/tools/remote-test-client", "remote-test-client";
     RustInstaller, "src/tools/rust-installer", "rust-installer";
@@ -481,7 +489,8 @@ bootstrap_tool!(
     GenerateCopyright, "src/tools/generate-copyright", "generate-copyright";
     SuggestTests, "src/tools/suggest-tests", "suggest-tests";
     GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys";
-    RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = "test";
+    // rustdoc-gui-test has a crate dependency on compiletest, so it needs the same unstable features.
+    RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES;
     CoverageDump, "src/tools/coverage-dump", "coverage-dump";
     WasmComponentLd, "src/tools/wasm-component-ld", "wasm-component-ld", is_unstable_tool = true, allow_features = "min_specialization";
     UnicodeTableGenerator, "src/tools/unicode-table-generator", "unicode-table-generator";
@@ -814,7 +823,6 @@ impl Step for LldWrapper {
             fields(build_compiler = ?self.build_compiler, target_compiler = ?self.target_compiler),
         ),
     )]
-
     fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
         if builder.config.dry_run() {
             return ToolBuildResult {
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
index a96ccdd12c2..e4503b26456 100644
--- a/src/bootstrap/src/core/builder/cargo.rs
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -260,7 +260,7 @@ impl Cargo {
             }
         }
 
-        for arg in linker_args(builder, compiler.host, LldThreads::Yes, 0) {
+        for arg in linker_args(builder, compiler.host, LldThreads::Yes) {
             self.hostflags.arg(&arg);
         }
 
@@ -270,10 +270,10 @@ impl Cargo {
         }
         // We want to set -Clinker using Cargo, therefore we only call `linker_flags` and not
         // `linker_args` here.
-        for flag in linker_flags(builder, target, LldThreads::Yes, compiler.stage) {
+        for flag in linker_flags(builder, target, LldThreads::Yes) {
             self.rustflags.arg(&flag);
         }
-        for arg in linker_args(builder, target, LldThreads::Yes, compiler.stage) {
+        for arg in linker_args(builder, target, LldThreads::Yes) {
             self.rustdocflags.arg(&arg);
         }
 
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index a9058f888d3..c32d9c2870c 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -101,13 +101,13 @@ pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash {
     /// Primary function to implement `Step` logic.
     ///
     /// This function can be triggered in two ways:
-    ///     1. Directly from [`Builder::execute_cli`].
-    ///     2. Indirectly by being called from other `Step`s using [`Builder::ensure`].
+    /// 1. Directly from [`Builder::execute_cli`].
+    /// 2. Indirectly by being called from other `Step`s using [`Builder::ensure`].
     ///
-    /// When called with [`Builder::execute_cli`] (as done by `Build::build`), this function executed twice:
-    ///     - First in "dry-run" mode to validate certain things (like cyclic Step invocations,
-    ///         directory creation, etc) super quickly.
-    ///     - Then it's called again to run the actual, very expensive process.
+    /// When called with [`Builder::execute_cli`] (as done by `Build::build`), this function is executed twice:
+    /// - First in "dry-run" mode to validate certain things (like cyclic Step invocations,
+    ///   directory creation, etc) super quickly.
+    /// - Then it's called again to run the actual, very expensive process.
     ///
     /// When triggered indirectly from other `Step`s, it may still run twice (as dry-run and real mode)
     /// depending on the `Step::run` implementation of the caller.
@@ -1276,7 +1276,6 @@ impl<'a> Builder<'a> {
             ),
         ),
     )]
-
     /// FIXME: This function is unnecessary (and dangerous, see <https://github.com/rust-lang/rust/issues/137469>).
     /// We already have uplifting logic for the compiler, so remove this.
     pub fn compiler_for(
@@ -1480,7 +1479,7 @@ impl<'a> Builder<'a> {
             cmd.arg("-Dwarnings");
         }
         cmd.arg("-Znormalize-docs");
-        cmd.args(linker_args(self, compiler.host, LldThreads::Yes, compiler.stage));
+        cmd.args(linker_args(self, compiler.host, LldThreads::Yes));
         cmd
     }
 
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 1712be7f947..2266e61bf60 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -189,7 +189,7 @@ pub enum GccCiMode {
 ///
 /// Note that this structure is not decoded directly into, but rather it is
 /// filled out from the decoded forms of the structs below. For documentation
-/// each field, see the corresponding fields in
+/// on each field, see the corresponding fields in
 /// `bootstrap.example.toml`.
 #[derive(Default, Clone)]
 pub struct Config {
@@ -417,6 +417,9 @@ pub struct Config {
     /// Command for visual diff display, e.g. `diff-tool --color=always`.
     pub compiletest_diff_tool: Option<String>,
 
+    /// Whether to use the precompiled stage0 libtest with compiletest.
+    pub compiletest_use_stage0_libtest: bool,
+
     pub is_running_on_ci: bool,
 }
 
@@ -983,6 +986,7 @@ define_config! {
         optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins",
         jobs: Option<u32> = "jobs",
         compiletest_diff_tool: Option<String> = "compiletest-diff-tool",
+        compiletest_use_stage0_libtest: Option<bool> = "compiletest-use-stage0-libtest",
         ccache: Option<StringOrBool> = "ccache",
         exclude: Option<Vec<PathBuf>> = "exclude",
     }
@@ -1540,9 +1544,6 @@ impl Config {
             }
         }
 
-        let file_content = t!(fs::read_to_string(config.src.join("src/ci/channel")));
-        let ci_channel = file_content.trim_end();
-
         // Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
         // but not if `bootstrap.toml` hasn't been created.
         let mut toml = if !using_default_path || toml_path.exists() {
@@ -1682,6 +1683,7 @@ impl Config {
             optimized_compiler_builtins,
             jobs,
             compiletest_diff_tool,
+            compiletest_use_stage0_libtest,
             mut ccache,
             exclude,
         } = toml.build.unwrap_or_default();
@@ -1847,17 +1849,21 @@ impl Config {
         let mut lld_enabled = None;
         let mut std_features = None;
 
-        let is_user_configured_rust_channel =
-            if let Some(channel) = toml.rust.as_ref().and_then(|r| r.channel.clone()) {
-                if channel == "auto-detect" {
-                    config.channel = ci_channel.into();
-                } else {
-                    config.channel = channel;
-                }
+        let file_content = t!(fs::read_to_string(config.src.join("src/ci/channel")));
+        let ci_channel = file_content.trim_end();
+
+        let toml_channel = toml.rust.as_ref().and_then(|r| r.channel.clone());
+        let is_user_configured_rust_channel = match toml_channel {
+            Some(channel) if channel == "auto-detect" => {
+                config.channel = ci_channel.into();
                 true
-            } else {
-                false
-            };
+            }
+            Some(channel) => {
+                config.channel = channel;
+                true
+            }
+            None => false,
+        };
 
         let default = config.channel == "dev";
         config.omit_git_hash = toml.rust.as_ref().and_then(|r| r.omit_git_hash).unwrap_or(default);
@@ -1882,6 +1888,10 @@ impl Config {
                 && config.src.join(".cargo/config.toml").exists(),
         );
 
+        if !is_user_configured_rust_channel && config.rust_info.is_from_tarball() {
+            config.channel = ci_channel.into();
+        }
+
         if let Some(rust) = toml.rust {
             let Rust {
                 optimize: optimize_toml,
@@ -2085,8 +2095,6 @@ impl Config {
 
                 config.channel = channel;
             }
-        } else if config.rust_info.is_from_tarball() && !is_user_configured_rust_channel {
-            ci_channel.clone_into(&mut config.channel);
         }
 
         if let Some(llvm) = toml.llvm {
@@ -2415,6 +2423,7 @@ impl Config {
         config.optimized_compiler_builtins =
             optimized_compiler_builtins.unwrap_or(config.channel != "dev");
         config.compiletest_diff_tool = compiletest_diff_tool;
+        config.compiletest_use_stage0_libtest = compiletest_use_stage0_libtest.unwrap_or(true);
 
         let download_rustc = config.download_rustc_commit.is_some();
         config.explicit_stage_from_cli = flags.stage.is_some();
@@ -2879,6 +2888,13 @@ impl Config {
 
         let absolute_path = self.src.join(relative_path);
 
+        // NOTE: This check is required because `jj git clone` doesn't create directories for
+        // submodules, they are completely ignored. The code below assumes this directory exists,
+        // so create it here.
+        if !absolute_path.exists() {
+            t!(fs::create_dir_all(&absolute_path));
+        }
+
         // NOTE: The check for the empty directory is here because when running x.py the first time,
         // the submodule won't be checked out. Check it out now so we can build it.
         if !GitInfo::new(false, &absolute_path).is_managed_git_subrepository()
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index 5bd947f6e63..4e4b948a8fd 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -417,7 +417,7 @@ enum DownloadSource {
     Dist,
 }
 
-/// Functions that are only ever called once, but named for clarify and to avoid thousand-line functions.
+/// Functions that are only ever called once, but named for clarity and to avoid thousand-line functions.
 impl Config {
     pub(crate) fn download_clippy(&self) -> PathBuf {
         self.verbose(|| println!("downloading stage0 clippy artifacts"));
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index dbfebd11f82..9e4a72bc9c3 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -34,7 +34,7 @@ pub struct Finder {
 // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap).
 const STAGE0_MISSING_TARGETS: &[&str] = &[
     // just a dummy comment so the list doesn't get onelined
-    "wasm32-wali-linux-musl",
+    "x86_64-lynx-lynxos178",
 ];
 
 /// Minimum version threshold for libstdc++ required when using prebuilt LLVM
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 843d474f92d..1a513a240e1 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -748,7 +748,7 @@ impl Build {
             features.push("llvm");
         }
         // keep in sync with `bootstrap/compile.rs:rustc_cargo_env`
-        if self.config.rust_randomize_layout {
+        if self.config.rust_randomize_layout && check("rustc_randomized_layouts") {
             features.push("rustc_randomized_layouts");
         }
 
@@ -1557,7 +1557,7 @@ Executed at: {executed_at}"#,
         !self.config.full_bootstrap
             && !self.config.download_rustc()
             && stage >= 2
-            && (self.hosts.iter().any(|h| *h == target) || target == self.build)
+            && (self.hosts.contains(&target) || target == self.build)
     }
 
     /// Checks whether the `compiler` compiling for `target` should be forced to
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 244391739f3..48b6f77e8a5 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -391,4 +391,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Info,
         summary: "You can now use `change-id = \"ignore\"` to suppress `change-id ` warnings in the console.",
     },
+    ChangeInfo {
+        change_id: 139386,
+        severity: ChangeSeverity::Info,
+        summary: "Added a new option `build.compiletest-use-stage0-libtest` to force `compiletest` to use the stage 0 libtest.",
+    },
 ];
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index f8e4d4e0471..1299fbb7d62 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -432,9 +432,7 @@ pub fn dir_is_empty(dir: &Path) -> bool {
 /// the "y" part from the string.
 pub fn extract_beta_rev(version: &str) -> Option<String> {
     let parts = version.splitn(2, "-beta.").collect::<Vec<_>>();
-    let count = parts.get(1).and_then(|s| s.find(' ').map(|p| s[..p].to_string()));
-
-    count
+    parts.get(1).and_then(|s| s.find(' ').map(|p| s[..p].to_string()))
 }
 
 pub enum LldThreads {
@@ -447,9 +445,8 @@ pub fn linker_args(
     builder: &Builder<'_>,
     target: TargetSelection,
     lld_threads: LldThreads,
-    stage: u32,
 ) -> Vec<String> {
-    let mut args = linker_flags(builder, target, lld_threads, stage);
+    let mut args = linker_flags(builder, target, lld_threads);
 
     if let Some(linker) = builder.linker(target) {
         args.push(format!("-Clinker={}", linker.display()));
@@ -464,23 +461,17 @@ pub fn linker_flags(
     builder: &Builder<'_>,
     target: TargetSelection,
     lld_threads: LldThreads,
-    stage: u32,
 ) -> Vec<String> {
     let mut args = vec![];
     if !builder.is_lld_direct_linker(target) && builder.config.lld_mode.is_used() {
         match builder.config.lld_mode {
             LldMode::External => {
-                // cfg(bootstrap) - remove after updating bootstrap compiler (#137498)
-                if stage == 0 && target.is_windows() {
-                    args.push("-Clink-arg=-fuse-ld=lld".to_string());
-                } else {
-                    args.push("-Clinker-flavor=gnu-lld-cc".to_string());
-                }
+                args.push("-Zlinker-features=+lld".to_string());
                 // FIXME(kobzol): remove this flag once MCP510 gets stabilized
                 args.push("-Zunstable-options".to_string());
             }
             LldMode::SelfContained => {
-                args.push("-Clinker-flavor=gnu-lld-cc".to_string());
+                args.push("-Zlinker-features=+lld".to_string());
                 args.push("-Clink-self-contained=+linker".to_string());
                 // FIXME(kobzol): remove this flag once MCP510 gets stabilized
                 args.push("-Zunstable-options".to_string());
@@ -503,9 +494,8 @@ pub fn add_rustdoc_cargo_linker_args(
     builder: &Builder<'_>,
     target: TargetSelection,
     lld_threads: LldThreads,
-    stage: u32,
 ) {
-    let args = linker_args(builder, target, lld_threads, stage);
+    let args = linker_args(builder, target, lld_threads);
     let mut flags = cmd
         .get_envs()
         .find_map(|(k, v)| if k == OsStr::new("RUSTDOCFLAGS") { v } else { None })
diff --git a/src/bootstrap/src/utils/proc_macro_deps.rs b/src/bootstrap/src/utils/proc_macro_deps.rs
index dbfd6f47dc6..7cf1af1c3e2 100644
--- a/src/bootstrap/src/utils/proc_macro_deps.rs
+++ b/src/bootstrap/src/utils/proc_macro_deps.rs
@@ -5,6 +5,7 @@ pub static CRATES: &[&str] = &[
     // tidy-alphabetical-start
     "annotate-snippets",
     "anstyle",
+    "askama_parser",
     "basic-toml",
     "block-buffer",
     "bumpalo",
@@ -31,7 +32,6 @@ pub static CRATES: &[&str] = &[
     "mime_guess",
     "minimal-lexical",
     "nom",
-    "num-conv",
     "once_cell",
     "pest",
     "pest_generator",
@@ -49,7 +49,6 @@ pub static CRATES: &[&str] = &[
     "syn",
     "synstructure",
     "thiserror",
-    "time-core",
     "tinystr",
     "type-map",
     "typenum",
@@ -64,6 +63,7 @@ pub static CRATES: &[&str] = &[
     "wasm-bindgen-backend",
     "wasm-bindgen-macro-support",
     "wasm-bindgen-shared",
+    "winnow",
     "yoke",
     "zerofrom",
     "zerovec",
diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs
index 693e0fc8f46..f5347c30824 100644
--- a/src/build_helper/src/git.rs
+++ b/src/build_helper/src/git.rs
@@ -114,7 +114,9 @@ fn git_upstream_merge_base(
     Ok(output_result(git.arg("merge-base").arg(&updated_master).arg("HEAD"))?.trim().to_owned())
 }
 
-/// Searches for the nearest merge commit in the repository that also exists upstream.
+/// Searches for the nearest merge commit in the repository.
+///
+/// **In CI** finds the nearest merge commit that *also exists upstream*.
 ///
 /// It looks for the most recent commit made by the merge bot by matching the author's email
 /// address with the merge bot's email.
@@ -165,7 +167,7 @@ pub fn get_closest_merge_commit(
     Ok(output_result(&mut git)?.trim().to_owned())
 }
 
-/// Returns the files that have been modified in the current branch compared to the master branch.
+/// Returns the files that have been modified in the current branch compared to the last merge.
 /// The `extensions` parameter can be used to filter the files by their extension.
 /// Does not include removed files.
 /// If `extensions` is empty, all files will be returned.
diff --git a/src/ci/citool/Cargo.lock b/src/ci/citool/Cargo.lock
index 800eaae0766..2fe219f368b 100644
--- a/src/ci/citool/Cargo.lock
+++ b/src/ci/citool/Cargo.lock
@@ -563,9 +563,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.8.5"
+version = "0.8.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5"
+checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
 dependencies = [
  "adler2",
 ]
diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs
index 7fbfad467c6..9fc7c309bfb 100644
--- a/src/ci/citool/src/analysis.rs
+++ b/src/ci/citool/src/analysis.rs
@@ -7,6 +7,7 @@ use build_helper::metrics::{
     format_build_steps,
 };
 
+use crate::github::JobInfoResolver;
 use crate::metrics;
 use crate::metrics::{JobMetrics, JobName, get_test_suites};
 use crate::utils::{output_details, pluralize};
@@ -185,13 +186,19 @@ fn render_table(suites: BTreeMap<String, TestSuiteRecord>) -> String {
 }
 
 /// Outputs a report of test differences between the `parent` and `current` commits.
-pub fn output_test_diffs(job_metrics: &HashMap<JobName, JobMetrics>) {
+pub fn output_test_diffs(
+    job_metrics: &HashMap<JobName, JobMetrics>,
+    job_info_resolver: &mut JobInfoResolver,
+) {
     let aggregated_test_diffs = aggregate_test_diffs(&job_metrics);
-    report_test_diffs(aggregated_test_diffs);
+    report_test_diffs(aggregated_test_diffs, job_metrics, job_info_resolver);
 }
 
 /// Prints the ten largest differences in bootstrap durations.
-pub fn output_largest_duration_changes(job_metrics: &HashMap<JobName, JobMetrics>) {
+pub fn output_largest_duration_changes(
+    job_metrics: &HashMap<JobName, JobMetrics>,
+    job_info_resolver: &mut JobInfoResolver,
+) {
     struct Entry<'a> {
         job: &'a JobName,
         before: Duration,
@@ -225,14 +232,14 @@ pub fn output_largest_duration_changes(job_metrics: &HashMap<JobName, JobMetrics
             });
         }
     }
-    changes.sort_by(|e1, e2| e1.change.partial_cmp(&e2.change).unwrap().reverse());
+    changes.sort_by(|e1, e2| e1.change.abs().partial_cmp(&e2.change.abs()).unwrap().reverse());
 
     println!("# Job duration changes");
     for (index, entry) in changes.into_iter().take(10).enumerate() {
         println!(
-            "{}. `{}`: {:.1}s -> {:.1}s ({:.1}%)",
+            "{}. {}: {:.1}s -> {:.1}s ({:.1}%)",
             index + 1,
-            entry.job,
+            format_job_link(job_info_resolver, job_metrics, entry.job),
             entry.before.as_secs_f64(),
             entry.after.as_secs_f64(),
             entry.change
@@ -400,7 +407,11 @@ fn generate_test_name(name: &str) -> String {
 }
 
 /// Prints test changes in Markdown format to stdout.
-fn report_test_diffs(diff: AggregatedTestDiffs) {
+fn report_test_diffs(
+    diff: AggregatedTestDiffs,
+    job_metrics: &HashMap<JobName, JobMetrics>,
+    job_info_resolver: &mut JobInfoResolver,
+) {
     println!("# Test differences");
     if diff.diffs.is_empty() {
         println!("No test diffs found");
@@ -509,21 +520,42 @@ fn report_test_diffs(diff: AggregatedTestDiffs) {
             }
 
             if doctest_count > 0 {
+                let prefix =
+                    if doctest_count < original_diff_count { "Additionally, " } else { "" };
                 println!(
-                    "\nAdditionally, {doctest_count} doctest {} were found. These are ignored, as they are noisy.",
+                    "\n{prefix}{doctest_count} doctest {} were found. These are ignored, as they are noisy.",
                     pluralize("diff", doctest_count)
                 );
             }
 
             // Now print the job group index
-            println!("\n**Job group index**\n");
-            for (group, jobs) in job_index.into_iter().enumerate() {
-                println!(
-                    "- {}: {}",
-                    format_job_group(group as u64),
-                    jobs.iter().map(|j| format!("`{j}`")).collect::<Vec<_>>().join(", ")
-                );
+            if !job_index.is_empty() {
+                println!("\n**Job group index**\n");
+                for (group, jobs) in job_index.into_iter().enumerate() {
+                    println!(
+                        "- {}: {}",
+                        format_job_group(group as u64),
+                        jobs.iter()
+                            .map(|j| format_job_link(job_info_resolver, job_metrics, j))
+                            .collect::<Vec<_>>()
+                            .join(", ")
+                    );
+                }
             }
         },
     );
 }
+
+/// Tries to get a GitHub Actions job summary URL from the resolver.
+/// If it is not available, just wraps the job name in backticks.
+fn format_job_link(
+    job_info_resolver: &mut JobInfoResolver,
+    job_metrics: &HashMap<JobName, JobMetrics>,
+    job_name: &str,
+) -> String {
+    job_metrics
+        .get(job_name)
+        .and_then(|metrics| job_info_resolver.get_job_summary_link(job_name, &metrics.current))
+        .map(|summary_url| format!("[{job_name}]({summary_url})"))
+        .unwrap_or_else(|| format!("`{job_name}`"))
+}
diff --git a/src/ci/citool/src/github.rs b/src/ci/citool/src/github.rs
new file mode 100644
index 00000000000..35e4c3f9599
--- /dev/null
+++ b/src/ci/citool/src/github.rs
@@ -0,0 +1,109 @@
+use std::collections::HashMap;
+
+use anyhow::Context;
+use build_helper::metrics::{CiMetadata, JsonRoot};
+
+pub struct GitHubClient;
+
+impl GitHubClient {
+    fn get_workflow_run_jobs(
+        &self,
+        repo: &str,
+        workflow_run_id: u64,
+    ) -> anyhow::Result<Vec<GitHubJob>> {
+        let req = ureq::get(format!(
+            "https://api.github.com/repos/{repo}/actions/runs/{workflow_run_id}/jobs?per_page=100"
+        ))
+        .header("User-Agent", "rust-lang/rust/citool")
+        .header("Accept", "application/vnd.github+json")
+        .header("X-GitHub-Api-Version", "2022-11-28")
+        .call()
+        .context("cannot get workflow job list")?;
+
+        let status = req.status();
+        let mut body = req.into_body();
+        if status.is_success() {
+            // This API response is actually paged, but we assume for now that there are at
+            // most 100 jobs per workflow.
+            let response = body
+                .read_json::<WorkflowRunJobsResponse>()
+                .context("cannot deserialize workflow run jobs response")?;
+            // The CI job names have a prefix, e.g. `auto - foo`. We remove the prefix here to
+            // normalize the job name.
+            Ok(response
+                .jobs
+                .into_iter()
+                .map(|mut job| {
+                    job.name = job
+                        .name
+                        .split_once(" - ")
+                        .map(|res| res.1.to_string())
+                        .unwrap_or_else(|| job.name);
+                    job
+                })
+                .collect())
+        } else {
+            Err(anyhow::anyhow!(
+                "Cannot get jobs of workflow run {workflow_run_id}: {status}\n{}",
+                body.read_to_string()?
+            ))
+        }
+    }
+}
+
+#[derive(serde::Deserialize)]
+struct WorkflowRunJobsResponse {
+    jobs: Vec<GitHubJob>,
+}
+
+#[derive(serde::Deserialize)]
+struct GitHubJob {
+    name: String,
+    id: u64,
+}
+
+/// Can be used to resolve information about GitHub Actions jobs.
+/// Caches results internally to avoid too unnecessary GitHub API calls.
+pub struct JobInfoResolver {
+    client: GitHubClient,
+    // Workflow run ID -> jobs
+    workflow_job_cache: HashMap<u64, Vec<GitHubJob>>,
+}
+
+impl JobInfoResolver {
+    pub fn new() -> Self {
+        Self { client: GitHubClient, workflow_job_cache: Default::default() }
+    }
+
+    /// Get a link to a job summary for the given job name and bootstrap execution.
+    pub fn get_job_summary_link(&mut self, job_name: &str, metrics: &JsonRoot) -> Option<String> {
+        metrics.ci_metadata.as_ref().and_then(|metadata| {
+            self.get_job_id(metadata, job_name).map(|job_id| {
+                format!(
+                    "https://github.com/{}/actions/runs/{}#summary-{job_id}",
+                    metadata.repository, metadata.workflow_run_id
+                )
+            })
+        })
+    }
+
+    fn get_job_id(&mut self, ci_metadata: &CiMetadata, job_name: &str) -> Option<u64> {
+        if let Some(job) = self
+            .workflow_job_cache
+            .get(&ci_metadata.workflow_run_id)
+            .and_then(|jobs| jobs.iter().find(|j| j.name == job_name))
+        {
+            return Some(job.id);
+        }
+
+        let jobs = self
+            .client
+            .get_workflow_run_jobs(&ci_metadata.repository, ci_metadata.workflow_run_id)
+            .inspect_err(|e| eprintln!("Cannot download workflow jobs: {e:?}"))
+            .ok()?;
+        let job_id = jobs.iter().find(|j| j.name == job_name).map(|j| j.id);
+        // Save the cache even if the job name was not found, it could be useful for further lookups
+        self.workflow_job_cache.insert(ci_metadata.workflow_run_id, jobs);
+        job_id
+    }
+}
diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs
index 6db5eab458c..a1956da352f 100644
--- a/src/ci/citool/src/main.rs
+++ b/src/ci/citool/src/main.rs
@@ -1,6 +1,7 @@
 mod analysis;
 mod cpu_usage;
 mod datadog;
+mod github;
 mod jobs;
 mod metrics;
 mod utils;
@@ -18,6 +19,7 @@ use serde_yaml::Value;
 use crate::analysis::{output_largest_duration_changes, output_test_diffs};
 use crate::cpu_usage::load_cpu_usage;
 use crate::datadog::upload_datadog_metric;
+use crate::github::JobInfoResolver;
 use crate::jobs::RunType;
 use crate::metrics::{JobMetrics, download_auto_job_metrics, download_job_metrics, load_metrics};
 use crate::utils::load_env_var;
@@ -145,6 +147,7 @@ fn postprocess_metrics(
 ) -> anyhow::Result<()> {
     let metrics = load_metrics(&metrics_path)?;
 
+    let mut job_info_resolver = JobInfoResolver::new();
     if let (Some(parent), Some(job_name)) = (parent, job_name) {
         // This command is executed also on PR builds, which might not have parent metrics
         // available, because some PR jobs don't run on auto builds, and PR jobs do not upload metrics
@@ -160,7 +163,7 @@ fn postprocess_metrics(
                     job_name,
                     JobMetrics { parent: Some(parent_metrics), current: metrics },
                 )]);
-                output_test_diffs(&job_metrics);
+                output_test_diffs(&job_metrics, &mut job_info_resolver);
                 return Ok(());
             }
             Err(error) => {
@@ -180,8 +183,10 @@ fn post_merge_report(db: JobDatabase, current: String, parent: String) -> anyhow
     let metrics = download_auto_job_metrics(&db, &parent, &current)?;
 
     println!("\nComparing {parent} (parent) -> {current} (this PR)\n");
-    output_test_diffs(&metrics);
-    output_largest_duration_changes(&metrics);
+
+    let mut job_info_resolver = JobInfoResolver::new();
+    output_test_diffs(&metrics, &mut job_info_resolver);
+    output_largest_duration_changes(&metrics, &mut job_info_resolver);
 
     Ok(())
 }
diff --git a/src/ci/citool/tests/test-jobs.yml b/src/ci/citool/tests/test-jobs.yml
index 3593b3f7df6..d81be88b708 100644
--- a/src/ci/citool/tests/test-jobs.yml
+++ b/src/ci/citool/tests/test-jobs.yml
@@ -27,7 +27,7 @@ runners:
     <<: *base-job
 envs:
   env-x86_64-apple-tests: &env-x86_64-apple-tests
-    SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact
+    SCRIPT: ./x.py check compiletest --set build.compiletest-use-stage0-libtest=true && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact
     RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc
     RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
     # Ensure that host tooling is tested on our minimum supported macOS version.
diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md
index 20b6f7d10ef..488a6a2bce1 100644
--- a/src/ci/docker/README.md
+++ b/src/ci/docker/README.md
@@ -14,9 +14,9 @@ To run a specific CI job locally, you can use the `citool` Rust crate:
 cargo run --manifest-path src/ci/citool/Cargo.toml run-local <job-name>
 ```
 
-For example, to run the `x86_64-gnu-llvm-18-1` job:
+For example, to run the `x86_64-gnu-llvm-19-1` job:
 ```
-cargo run --manifest-path src/ci/citool/Cargo.toml run-local x86_64-gnu-llvm-18-1
+cargo run --manifest-path src/ci/citool/Cargo.toml run-local x86_64-gnu-llvm-19-1
 ```
 
 The job will output artifacts in an `obj/<image-name>` dir at the root of a repository. Note
@@ -27,10 +27,10 @@ Docker image executed in the given CI job.
 while locally, to the `obj/<image-name>` directory. This is primarily to prevent
 strange linker errors when using multiple Docker images.
 
-For some Linux workflows (for example `x86_64-gnu-llvm-18-N`), the process is more involved. You will need to see which script is executed for the given workflow inside the [`jobs.yml`](../github-actions/jobs.yml) file and pass it through the `DOCKER_SCRIPT` environment variable. For example, to reproduce the `x86_64-gnu-llvm-18-3` workflow, you can run the following script:
+For some Linux workflows (for example `x86_64-gnu-llvm-19-N`), the process is more involved. You will need to see which script is executed for the given workflow inside the [`jobs.yml`](../github-actions/jobs.yml) file and pass it through the `DOCKER_SCRIPT` environment variable. For example, to reproduce the `x86_64-gnu-llvm-19-3` workflow, you can run the following script:
 
 ```
-DOCKER_SCRIPT=x86_64-gnu-llvm3.sh ./src/ci/docker/run.sh x86_64-gnu-llvm-18
+DOCKER_SCRIPT=x86_64-gnu-llvm3.sh ./src/ci/docker/run.sh x86_64-gnu-llvm-19
 ```
 
 ## Local Development
diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
index b32fa6c8e4e..418408e9242 100644
--- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
@@ -47,7 +47,8 @@ COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/
 ENV SCRIPT \
            python3 ../x.py check --stage 0 --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \
            /scripts/check-default-config-profiles.sh && \
-           python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \
+           python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \
+           python3 ../x.py check --target=x86_64-pc-windows-gnu --host=x86_64-pc-windows-gnu && \
            python3 ../x.py clippy ci && \
            python3 ../x.py build --stage 0 src/tools/build-manifest && \
            python3 ../x.py test --stage 0 src/tools/compiletest && \
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile
index e0ed2e227f8..be235f648b5 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile
@@ -3,6 +3,7 @@ FROM ubuntu:24.10
 ARG DEBIAN_FRONTEND=noninteractive
 
 RUN apt-get update && apt-get install -y --no-install-recommends \
+  bzip2 \
   g++ \
   gcc-multilib \
   make \
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-18/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile
index aefc0f376f6..408b87125e0 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-18/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile
@@ -1,4 +1,4 @@
-FROM ubuntu:24.04
+FROM ubuntu:25.04
 
 ARG DEBIAN_FRONTEND=noninteractive
 
@@ -16,8 +16,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   cmake \
   sudo \
   gdb \
-  llvm-18-tools \
-  llvm-18-dev \
+  llvm-20-tools \
+  llvm-20-dev \
   libedit-dev \
   libssl-dev \
   pkg-config \
@@ -50,7 +50,7 @@ ENV EXTERNAL_LLVM 1
 # Using llvm-link-shared due to libffi issues -- see #34486
 ENV RUST_CONFIGURE_ARGS \
       --build=x86_64-unknown-linux-gnu \
-      --llvm-root=/usr/lib/llvm-18 \
+      --llvm-root=/usr/lib/llvm-20 \
       --enable-llvm-link-shared \
       --set rust.randomize-layout=true \
       --set rust.thin-lto-import-instr-limit=10
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
index 89806634c6c..05c90af7807 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
@@ -101,4 +101,5 @@ COPY scripts/shared.sh /scripts/
 # the local version of the package is different than the one used by the CI.
 ENV SCRIPT /tmp/checktools.sh ../x.py && \
   npm install browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true && \
+  python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \
   python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--jobs 1'"
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh
index 8324d1ec586..28c035daa5d 100755
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh
@@ -62,7 +62,6 @@ case $HOST_TARGET in
     # See <https://github.com/rust-lang/rust/issues/127883>
     # For now, these tests are moved to `x86_64-msvc-ext2` in `src/ci/github-actions/jobs.yml`.
     #python3 "$X_PY" test --stage 2 src/tools/miri --target aarch64-apple-darwin --test-args pass
-    #python3 "$X_PY" test --stage 2 src/tools/miri --target i686-pc-windows-gnu --test-args pass
     ;;
   *)
     echo "FATAL: unexpected host $HOST_TARGET"
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index f62ed23d038..cb2bec5a9df 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -23,8 +23,8 @@ runners:
     os: ubuntu-24.04-16core-64gb
     <<: *base-job
 
-  - &job-macos-xl
-    os: macos-13 # We use the standard runner for now
+  - &job-macos
+    os: macos-13
     <<: *base-job
 
   - &job-macos-m1
@@ -58,7 +58,7 @@ runners:
     <<: *base-job
 envs:
   env-x86_64-apple-tests: &env-x86_64-apple-tests
-    SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact
+    SCRIPT: ./x.py check compiletest --set build.compiletest-use-stage0-libtest=true && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact
     RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc
     RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
     # Ensure that host tooling is tested on our minimum supported macOS version.
@@ -105,7 +105,7 @@ pr:
   - name: mingw-check-tidy
     continue_on_error: true
     <<: *job-linux-4c
-  - name: x86_64-gnu-llvm-18
+  - name: x86_64-gnu-llvm-19
     env:
       ENABLE_GCC_CODEGEN: "1"
       # We are adding (temporarily) a dummy commit on the compiler
@@ -304,56 +304,53 @@ auto:
   - name: x86_64-gnu-distcheck
     <<: *job-linux-8c
 
-  # The x86_64-gnu-llvm-19 job is split into multiple jobs to run tests in parallel.
-  # x86_64-gnu-llvm-19-1 skips tests that run in x86_64-gnu-llvm-19-{2,3}.
-  - name: x86_64-gnu-llvm-19-1
+  # The x86_64-gnu-llvm-20 job is split into multiple jobs to run tests in parallel.
+  # x86_64-gnu-llvm-20-1 skips tests that run in x86_64-gnu-llvm-20-{2,3}.
+  - name: x86_64-gnu-llvm-20-1
     env:
       RUST_BACKTRACE: 1
-      IMAGE: x86_64-gnu-llvm-19
+      IMAGE: x86_64-gnu-llvm-20
       DOCKER_SCRIPT: stage_2_test_set1.sh
     <<: *job-linux-4c
 
-  # Skip tests that run in x86_64-gnu-llvm-19-{1,3}
-  - name: x86_64-gnu-llvm-19-2
+  # Skip tests that run in x86_64-gnu-llvm-20-{1,3}
+  - name: x86_64-gnu-llvm-20-2
     env:
       RUST_BACKTRACE: 1
-      IMAGE: x86_64-gnu-llvm-19
+      IMAGE: x86_64-gnu-llvm-20
       DOCKER_SCRIPT: x86_64-gnu-llvm2.sh
     <<: *job-linux-4c
 
-  # Skip tests that run in x86_64-gnu-llvm-19-{1,2}
-  - name: x86_64-gnu-llvm-19-3
+  # Skip tests that run in x86_64-gnu-llvm-20-{1,2}
+  - name: x86_64-gnu-llvm-20-3
     env:
       RUST_BACKTRACE: 1
-      IMAGE: x86_64-gnu-llvm-19
+      IMAGE: x86_64-gnu-llvm-20
       DOCKER_SCRIPT: x86_64-gnu-llvm3.sh
     <<: *job-linux-4c
 
-  # The x86_64-gnu-llvm-18 job is split into multiple jobs to run tests in parallel.
-  # x86_64-gnu-llvm-18-1 skips tests that run in x86_64-gnu-llvm-18-{2,3}.
-  - name: x86_64-gnu-llvm-18-1
+  # The x86_64-gnu-llvm-19 job is split into multiple jobs to run tests in parallel.
+  # x86_64-gnu-llvm-19-1 skips tests that run in x86_64-gnu-llvm-19-{2,3}.
+  - name: x86_64-gnu-llvm-19-1
     env:
       RUST_BACKTRACE: 1
-      READ_ONLY_SRC: "0"
-      IMAGE: x86_64-gnu-llvm-18
+      IMAGE: x86_64-gnu-llvm-19
       DOCKER_SCRIPT: stage_2_test_set1.sh
     <<: *job-linux-4c
 
-  # Skip tests that run in x86_64-gnu-llvm-18-{1,3}
-  - name: x86_64-gnu-llvm-18-2
+  # Skip tests that run in x86_64-gnu-llvm-19-{1,3}
+  - name: x86_64-gnu-llvm-19-2
     env:
       RUST_BACKTRACE: 1
-      READ_ONLY_SRC: "0"
-      IMAGE: x86_64-gnu-llvm-18
+      IMAGE: x86_64-gnu-llvm-19
       DOCKER_SCRIPT: x86_64-gnu-llvm2.sh
     <<: *job-linux-4c
 
-  # Skip tests that run in x86_64-gnu-llvm-18-{1,2}
-  - name: x86_64-gnu-llvm-18-3
+  # Skip tests that run in x86_64-gnu-llvm-19-{1,2}
+  - name: x86_64-gnu-llvm-19-3
     env:
       RUST_BACKTRACE: 1
-      READ_ONLY_SRC: "0"
-      IMAGE: x86_64-gnu-llvm-18
+      IMAGE: x86_64-gnu-llvm-19
       DOCKER_SCRIPT: x86_64-gnu-llvm3.sh
     <<: *job-linux-4c
 
@@ -383,7 +380,7 @@ auto:
       NO_OVERFLOW_CHECKS: 1
       DIST_REQUIRE_ALL_TOOLS: 1
       CODEGEN_BACKENDS: llvm,cranelift
-    <<: *job-macos-xl
+    <<: *job-macos
 
   - name: dist-apple-various
     env:
@@ -400,18 +397,18 @@ auto:
       NO_LLVM_ASSERTIONS: 1
       NO_DEBUG_ASSERTIONS: 1
       NO_OVERFLOW_CHECKS: 1
-    <<: *job-macos-xl
+    <<: *job-macos
 
   - name: x86_64-apple-1
     env:
       <<: *env-x86_64-apple-tests
-    <<: *job-macos-xl
+    <<: *job-macos
 
   - name: x86_64-apple-2
     env:
       SCRIPT: ./x.py --stage 2 test tests/ui tests/rustdoc
       <<: *env-x86_64-apple-tests
-    <<: *job-macos-xl
+    <<: *job-macos
 
   - name: dist-aarch64-apple
     env:
@@ -501,7 +498,7 @@ auto:
     env:
       SCRIPT: >
         python x.py test --stage 2 src/tools/miri --target aarch64-apple-darwin --test-args pass &&
-        python x.py test --stage 2 src/tools/miri --target i686-pc-windows-gnu --test-args pass &&
+        python x.py test --stage 2 src/tools/miri --target x86_64-pc-windows-gnu --test-args pass &&
         python x.py miri --stage 2 library/core --test-args notest &&
         python x.py miri --stage 2 library/alloc --test-args notest &&
         python x.py miri --stage 2 library/std --test-args notest
@@ -533,31 +530,6 @@ auto:
   # came from the mingw-w64 SourceForge download site. Unfortunately
   # SourceForge is notoriously flaky, so we mirror it on our own infrastructure.
 
-  # i686-mingw is split into three jobs to run tests in parallel.
-  - name: i686-mingw-1
-    env:
-      RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
-      SCRIPT: make ci-mingw-x-1
-      # There is no dist-i686-mingw-alt, so there is no prebuilt LLVM with assertions
-      NO_DOWNLOAD_CI_LLVM: 1
-    <<: *job-windows-25
-
-  - name: i686-mingw-2
-    env:
-      RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
-      SCRIPT: make ci-mingw-x-2
-      # There is no dist-i686-mingw-alt, so there is no prebuilt LLVM with assertions
-      NO_DOWNLOAD_CI_LLVM: 1
-    <<: *job-windows-25
-
-  - name: i686-mingw-3
-    env:
-      RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
-      SCRIPT: make ci-mingw-bootstrap
-      # There is no dist-i686-mingw-alt, so there is no prebuilt LLVM with assertions
-      NO_DOWNLOAD_CI_LLVM: 1
-    <<: *job-windows-25
-
   # x86_64-mingw is split into two jobs to run tests in parallel.
   - name: x86_64-mingw-1
     env:
diff --git a/src/doc/book b/src/doc/book
-Subproject 45f05367360f033f89235eacbbb54e8d73ce6b7
+Subproject d33916341d480caede1d0ae57cbeae23aab23e8
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
-Subproject 1e27e5e6d5133ae4612f5cc195c15fc8d51b1c9
+Subproject 467f45637b73ec6aa70fb36bc3054bb50b8967e
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject b4448fa406a6dccde62d1e2f34f70fc51814cdc
+Subproject 0c10c30cc54736c5c194ce98c50e2de84eeb6e7
diff --git a/src/doc/reference b/src/doc/reference
-Subproject e95ebdfee02514d93f79ec92ae310a804e87f01
+Subproject 3340922df189bddcbaad17dc3927d51a76bcd5e
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 6f69823c28ae8d929d6c815181c73d3e99ef16d
+Subproject 0d7964d5b22cf920237ef1282d869564b4883b8
diff --git a/src/doc/rustc-dev-guide/.github/workflows/ci.yml b/src/doc/rustc-dev-guide/.github/workflows/ci.yml
index 22a4fb1901a..415d0dc397d 100644
--- a/src/doc/rustc-dev-guide/.github/workflows/ci.yml
+++ b/src/doc/rustc-dev-guide/.github/workflows/ci.yml
@@ -18,6 +18,7 @@ jobs:
       MDBOOK_LINKCHECK2_VERSION: 0.9.1
       MDBOOK_MERMAID_VERSION: 0.12.6
       MDBOOK_TOC_VERSION: 0.11.2
+      MDBOOK_OUTPUT__LINKCHECK__FOLLOW_WEB_LINKS: ${{ github.event_name != 'pull_request' }}
       DEPLOY_DIR: book/html
       BASE_SHA: ${{ github.event.pull_request.base.sha }}
       GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/src/doc/rustc-dev-guide/book.toml b/src/doc/rustc-dev-guide/book.toml
index 67069d9930f..b84b1e7548a 100644
--- a/src/doc/rustc-dev-guide/book.toml
+++ b/src/doc/rustc-dev-guide/book.toml
@@ -1,6 +1,6 @@
 [book]
 title = "Rust Compiler Development Guide"
-author = "The Rust Project Developers"
+authors = ["The Rust Project Developers"]
 description = "A guide to developing the Rust compiler (rustc)"
 
 [build]
@@ -62,5 +62,7 @@ warning-policy = "error"
 "/diagnostics/sessiondiagnostic.html" = "diagnostic-structs.html"
 "/diagnostics/diagnostic-codes.html" = "error-codes.html"
 "/miri.html" = "const-eval/interpret.html"
-"/tests/integration.html" = "ecosystem.html"
+"/tests/fuchsia.html" = "ecosystem-test-jobs/fuchsia.html"
 "/tests/headers.html" = "directives.html"
+"/tests/integration.html" = "ecosystem.html"
+"/tests/rust-for-linux.html" = "ecosystem-test-jobs/rust-for-linux.html"
diff --git a/src/doc/rustc-dev-guide/ci/date-check/src/main.rs b/src/doc/rustc-dev-guide/ci/date-check/src/main.rs
index 5ab3e6c8b65..9af69dbbf3f 100644
--- a/src/doc/rustc-dev-guide/ci/date-check/src/main.rs
+++ b/src/doc/rustc-dev-guide/ci/date-check/src/main.rs
@@ -1,11 +1,8 @@
-use std::{
-    collections::BTreeMap,
-    convert::TryInto as _,
-    env, fmt, fs,
-    path::{Path, PathBuf},
-    process,
-    str::FromStr,
-};
+use std::collections::BTreeMap;
+use std::convert::TryInto as _;
+use std::path::{Path, PathBuf};
+use std::str::FromStr;
+use std::{env, fmt, fs, process};
 
 use chrono::{Datelike as _, Month, TimeZone as _, Utc};
 use glob::glob;
@@ -19,19 +16,13 @@ struct Date {
 
 impl Date {
     fn months_since(self, other: Date) -> Option<u32> {
-        let self_chrono = Utc
-            .with_ymd_and_hms(self.year.try_into().unwrap(), self.month, 1, 0, 0, 0)
-            .unwrap();
-        let other_chrono = Utc
-            .with_ymd_and_hms(other.year.try_into().unwrap(), other.month, 1, 0, 0, 0)
-            .unwrap();
+        let self_chrono =
+            Utc.with_ymd_and_hms(self.year.try_into().unwrap(), self.month, 1, 0, 0, 0).unwrap();
+        let other_chrono =
+            Utc.with_ymd_and_hms(other.year.try_into().unwrap(), other.month, 1, 0, 0, 0).unwrap();
         let duration_since = self_chrono.signed_duration_since(other_chrono);
         let months_since = duration_since.num_days() / 30;
-        if months_since < 0 {
-            None
-        } else {
-            Some(months_since.try_into().unwrap())
-        }
+        if months_since < 0 { None } else { Some(months_since.try_into().unwrap()) }
     }
 }
 
@@ -66,26 +57,18 @@ fn collect_dates_from_file(date_regex: &Regex, text: &str) -> Vec<(usize, Date)>
     date_regex
         .captures_iter(text)
         .filter_map(|cap| {
-            if let (Some(month), Some(year), None, None) | (None, None, Some(month), Some(year)) = (
-                cap.name("m1"),
-                cap.name("y1"),
-                cap.name("m2"),
-                cap.name("y2"),
-            ) {
+            if let (Some(month), Some(year), None, None) | (None, None, Some(month), Some(year)) =
+                (cap.name("m1"), cap.name("y1"), cap.name("m2"), cap.name("y2"))
+            {
                 let year = year.as_str().parse().expect("year");
-                let month = Month::from_str(month.as_str())
-                    .expect("month")
-                    .number_from_month();
+                let month = Month::from_str(month.as_str()).expect("month").number_from_month();
                 Some((cap.get(0).expect("all").range(), Date { year, month }))
             } else {
                 None
             }
         })
         .map(|(byte_range, date)| {
-            line += text[end_of_last_cap..byte_range.end]
-                .chars()
-                .filter(|c| *c == '\n')
-                .count();
+            line += text[end_of_last_cap..byte_range.end].chars().filter(|c| *c == '\n').count();
             end_of_last_cap = byte_range.end;
             (line, date)
         })
@@ -138,10 +121,7 @@ fn main() {
     let root_dir_path = Path::new(&root_dir);
     let glob_pat = format!("{}/**/*.md", root_dir);
     let today_chrono = Utc::now().date_naive();
-    let current_month = Date {
-        year: today_chrono.year_ce().1,
-        month: today_chrono.month(),
-    };
+    let current_month = Date { year: today_chrono.year_ce().1, month: today_chrono.month() };
 
     let dates_by_file = collect_dates(glob(&glob_pat).unwrap().map(Result::unwrap));
     let dates_by_file: BTreeMap<_, _> =
@@ -173,10 +153,7 @@ fn main() {
         println!();
 
         for (path, dates) in dates_by_file {
-            println!(
-                "- {}",
-                path.strip_prefix(&root_dir_path).unwrap_or(&path).display(),
-            );
+            println!("- {}", path.strip_prefix(&root_dir_path).unwrap_or(&path).display(),);
             for (line, date) in dates {
                 println!("  - [ ] line {}: {}", line, date);
             }
@@ -191,14 +168,8 @@ mod tests {
 
     #[test]
     fn test_months_since() {
-        let date1 = Date {
-            year: 2020,
-            month: 3,
-        };
-        let date2 = Date {
-            year: 2021,
-            month: 1,
-        };
+        let date1 = Date { year: 2020, month: 3 };
+        let date2 = Date { year: 2021, month: 1 };
         assert_eq!(date2.months_since(date1), Some(10));
     }
 
@@ -273,83 +244,17 @@ Test8
         assert_eq!(
             collect_dates_from_file(&make_date_regex(), text),
             vec![
-                (
-                    3,
-                    Date {
-                        year: 2021,
-                        month: 1,
-                    }
-                ),
-                (
-                    6,
-                    Date {
-                        year: 2021,
-                        month: 2,
-                    }
-                ),
-                (
-                    9,
-                    Date {
-                        year: 2021,
-                        month: 3,
-                    }
-                ),
-                (
-                    11,
-                    Date {
-                        year: 2021,
-                        month: 4,
-                    }
-                ),
-                (
-                    17,
-                    Date {
-                        year: 2021,
-                        month: 5,
-                    }
-                ),
-                (
-                    20,
-                    Date {
-                        year: 2021,
-                        month: 1,
-                    }
-                ),
-                (
-                    23,
-                    Date {
-                        year: 2021,
-                        month: 2,
-                    }
-                ),
-                (
-                    26,
-                    Date {
-                        year: 2021,
-                        month: 3,
-                    }
-                ),
-                (
-                    28,
-                    Date {
-                        year: 2021,
-                        month: 4,
-                    }
-                ),
-                (
-                    34,
-                    Date {
-                        year: 2021,
-                        month: 5,
-                    }
-                ),
-                (
-                    38,
-                    Date {
-                        year: 2021,
-                        month: 6,
-                    }
-                ),
+                (3, Date { year: 2021, month: 1 }),
+                (6, Date { year: 2021, month: 2 }),
+                (9, Date { year: 2021, month: 3 }),
+                (11, Date { year: 2021, month: 4 }),
+                (17, Date { year: 2021, month: 5 }),
+                (20, Date { year: 2021, month: 1 }),
+                (23, Date { year: 2021, month: 2 }),
+                (26, Date { year: 2021, month: 3 }),
+                (28, Date { year: 2021, month: 4 }),
+                (34, Date { year: 2021, month: 5 }),
+                (38, Date { year: 2021, month: 6 }),
             ],
         );
     }
diff --git a/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs b/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs
index 984bd3e37ae..db6ac185785 100644
--- a/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs
+++ b/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs
@@ -1,4 +1,4 @@
-// Tested with nightly-2025-02-13
+// Tested with nightly-2025-03-28
 
 #![feature(rustc_private)]
 
@@ -34,9 +34,9 @@ impl rustc_span::source_map::FileLoader for MyFileLoader {
     fn read_file(&self, path: &Path) -> io::Result<String> {
         if path == Path::new("main.rs") {
             Ok(r#"
+static MESSAGE: &str = "Hello, World!";
 fn main() {
-    let message = "Hello, World!";
-    println!("{message}");
+    println!("{MESSAGE}");
 }
 "#
             .to_string())
@@ -71,14 +71,12 @@ impl rustc_driver::Callbacks for MyCallbacks {
 
     fn after_analysis(&mut self, _compiler: &Compiler, tcx: TyCtxt<'_>) -> Compilation {
         // Analyze the program and inspect the types of definitions.
-        for id in tcx.hir().items() {
-            let hir = tcx.hir();
-            let item = hir.item(id);
+        for id in tcx.hir_free_items() {
+            let item = &tcx.hir_item(id);
             match item.kind {
-                rustc_hir::ItemKind::Static(_, _, _) | rustc_hir::ItemKind::Fn { .. } => {
-                    let name = item.ident;
+                rustc_hir::ItemKind::Static(ident, ..) | rustc_hir::ItemKind::Fn { ident, .. } => {
                     let ty = tcx.type_of(item.hir_id().owner.def_id);
-                    println!("{name:?}:\t{ty:?}")
+                    println!("{ident:?}:\t{ty:?}")
                 }
                 _ => (),
             }
diff --git a/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs b/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs
index 3270c722e07..c0d7f977d35 100644
--- a/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs
+++ b/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs
@@ -1,4 +1,4 @@
-// Tested with nightly-2025-02-13
+// Tested with nightly-2025-03-28
 
 #![feature(rustc_private)]
 
@@ -20,7 +20,7 @@ use std::path::Path;
 use std::sync::Arc;
 
 use rustc_ast_pretty::pprust::item_to_string;
-use rustc_driver::{run_compiler, Compilation};
+use rustc_driver::{Compilation, run_compiler};
 use rustc_interface::interface::{Compiler, Config};
 use rustc_middle::ty::TyCtxt;
 
@@ -70,11 +70,9 @@ impl rustc_driver::Callbacks for MyCallbacks {
     }
 
     fn after_analysis(&mut self, _compiler: &Compiler, tcx: TyCtxt<'_>) -> Compilation {
-        // Every compilation contains a single crate.
-        let hir_krate = tcx.hir();
         // Iterate over the top-level items in the crate, looking for the main function.
-        for id in hir_krate.items() {
-            let item = hir_krate.item(id);
+        for id in tcx.hir_free_items() {
+            let item = &tcx.hir_item(id);
             // Use pattern-matching to find a specific node inside the main function.
             if let rustc_hir::ItemKind::Fn { body, .. } = item.kind {
                 let expr = &tcx.hir_body(body).value;
diff --git a/src/doc/rustc-dev-guide/examples/rustc-interface-example.rs b/src/doc/rustc-dev-guide/examples/rustc-interface-example.rs
index 70f27c2a82a..360f70c8e86 100644
--- a/src/doc/rustc-dev-guide/examples/rustc-interface-example.rs
+++ b/src/doc/rustc-dev-guide/examples/rustc-interface-example.rs
@@ -1,4 +1,4 @@
-// Tested with nightly-2025-02-13
+// Tested with nightly-2025-03-28
 
 #![feature(rustc_private)]
 
@@ -64,14 +64,13 @@ fn main() {
         println!("{krate:?}");
         // Analyze the program and inspect the types of definitions.
         rustc_interface::create_and_enter_global_ctxt(&compiler, krate, |tcx| {
-            for id in tcx.hir().items() {
-                let hir = tcx.hir();
-                let item = hir.item(id);
+            for id in tcx.hir_free_items() {
+                let item = tcx.hir_item(id);
                 match item.kind {
-                    rustc_hir::ItemKind::Static(_, _, _) | rustc_hir::ItemKind::Fn { .. } => {
-                        let name = item.ident;
+                    rustc_hir::ItemKind::Static(ident, ..)
+                    | rustc_hir::ItemKind::Fn { ident, .. } => {
                         let ty = tcx.type_of(item.hir_id().owner.def_id);
-                        println!("{name:?}:\t{ty:?}")
+                        println!("{ident:?}:\t{ty:?}")
                     }
                     _ => (),
                 }
diff --git a/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs b/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs
index 39b236e1783..2512ba3c3f9 100644
--- a/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs
+++ b/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs
@@ -1,4 +1,4 @@
-// Tested with nightly-2025-02-13
+// Tested with nightly-2025-03-28
 
 #![feature(rustc_private)]
 
@@ -86,8 +86,10 @@ fn main() {
     rustc_interface::run_compiler(config, |compiler| {
         let krate = rustc_interface::passes::parse(&compiler.sess);
         rustc_interface::create_and_enter_global_ctxt(&compiler, krate, |tcx| {
-            // Run the analysis phase on the local crate to trigger the type error.
-            let _ = tcx.analysis(());
+            // Iterate all the items defined and perform type checking.
+            tcx.par_hir_body_owners(|item_def_id| {
+                tcx.ensure_ok().typeck(item_def_id);
+            });
         });
         // If the compiler has encountered errors when this closure returns, it will abort (!) the program.
         // We avoid this by resetting the error count before returning
diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version
index 6baf43397e8..a6f29510879 100644
--- a/src/doc/rustc-dev-guide/rust-version
+++ b/src/doc/rustc-dev-guide/rust-version
@@ -1 +1 @@
-493c38ba371929579fe136df26eccd9516347c7a
+25a615bf829b9f6d6f22da537e3851043f92e5f2
diff --git a/src/doc/rustc-dev-guide/rustfmt.toml b/src/doc/rustc-dev-guide/rustfmt.toml
new file mode 100644
index 00000000000..b285329c78e
--- /dev/null
+++ b/src/doc/rustc-dev-guide/rustfmt.toml
@@ -0,0 +1,7 @@
+# matches that of rust-lang/rust
+style_edition = "2024"
+use_small_heuristics = "Max"
+merge_derives = false
+group_imports = "StdExternalCrate"
+imports_granularity = "Module"
+use_field_init_shorthand = true
diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md
index ce74c741b39..95a3cd7c790 100644
--- a/src/doc/rustc-dev-guide/src/SUMMARY.md
+++ b/src/doc/rustc-dev-guide/src/SUMMARY.md
@@ -28,8 +28,11 @@
         - [Minicore](./tests/minicore.md)
     - [Ecosystem testing](./tests/ecosystem.md)
         - [Crater](./tests/crater.md)
-        - [Fuchsia](./tests/fuchsia.md)
-        - [Rust for Linux](./tests/rust-for-linux.md)
+        - [Fuchsia](./tests/ecosystem-test-jobs/fuchsia.md)
+        - [Rust for Linux](./tests/ecosystem-test-jobs/rust-for-linux.md)
+    - [Codegen backend testing](./tests/codegen-backend-tests/intro.md)
+        - [Cranelift codegen backend](./tests/codegen-backend-tests/cg_clif.md)
+        - [GCC codegen backend](./tests/codegen-backend-tests/cg_gcc.md)
     - [Performance testing](./tests/perf.md)
     - [Suggest tests tool](./tests/suggest-tests.md)
     - [Misc info](./tests/misc.md)
@@ -61,12 +64,13 @@
     - [ARM](notification-groups/arm.md)
     - [Cleanup Crew](notification-groups/cleanup-crew.md)
     - [Emscripten](notification-groups/emscripten.md)
+    - [Fuchsia](notification-groups/fuchsia.md)
     - [LLVM](notification-groups/llvm.md)
     - [RISC-V](notification-groups/risc-v.md)
+    - [Rust for Linux](notification-groups/rust-for-linux.md)
     - [WASI](notification-groups/wasi.md)
     - [WebAssembly](notification-groups/wasm.md)
     - [Windows](notification-groups/windows.md)
-    - [Rust for Linux](notification-groups/rust-for-linux.md)
 - [Licenses](./licenses.md)
 - [Editions](guides/editions.md)
 
@@ -94,7 +98,7 @@
 - [Parallel Compilation](./parallel-rustc.md)
 - [Rustdoc internals](./rustdoc-internals.md)
     - [Search](./rustdoc-internals/search.md)
-
+	- [The `rustdoc` test suite](./rustdoc-internals/rustdoc-test-suite.md)
 # Source Code Representation
 
 - [Prologue](./part-3-intro.md)
@@ -124,6 +128,7 @@
 - [rustc_driver and rustc_interface](./rustc-driver/intro.md)
     - [Example: Type checking](./rustc-driver/interacting-with-the-ast.md)
     - [Example: Getting diagnostics](./rustc-driver/getting-diagnostics.md)
+    - [Remarks on perma-unstable features](./rustc-driver/remarks-on-perma-unstable-features.md)
 - [Errors and Lints](diagnostics.md)
     - [Diagnostic and subdiagnostic structs](./diagnostics/diagnostic-structs.md)
     - [Translation](./diagnostics/translation.md)
@@ -144,10 +149,7 @@
     - [ADTs and Generic Arguments](./ty_module/generic_arguments.md)
     - [Parameter types/consts/regions](./ty_module/param_ty_const_regions.md)
 - [`TypeFolder` and `TypeFoldable`](./ty-fold.md)
-- [Parameter Environments](./param_env/param_env_summary.md)
-    - [What is it?](./param_env/param_env_what_is_it.md)
-    - [How are `ParamEnv`'s constructed internally](./param_env/param_env_construction_internals.md)
-    - [Which `ParamEnv` do I use?](./param_env/param_env_acquisition.md)
+- [Typing/Param Envs](./typing_parameter_envs.md)
 - [Type inference](./type-inference.md)
 - [Trait solving](./traits/resolution.md)
     - [Higher-ranked trait bounds](./traits/hrtb.md)
diff --git a/src/doc/rustc-dev-guide/src/appendix/code-index.md b/src/doc/rustc-dev-guide/src/appendix/code-index.md
index b96ede68eab..65fbf752d79 100644
--- a/src/doc/rustc-dev-guide/src/appendix/code-index.md
+++ b/src/doc/rustc-dev-guide/src/appendix/code-index.md
@@ -40,5 +40,5 @@ Item            |  Kind    | Short description           | Chapter            |
 [Emitting Diagnostics]: ../diagnostics.html
 [Macro expansion]: ../macro-expansion.html
 [Name resolution]: ../name-resolution.html
-[Parameter Environment]: ../param_env/param_env_summary.html
+[Parameter Environment]: ../typing_parameter_envs.html
 [Trait Solving: Goals and Clauses]: ../traits/goals-and-clauses.html#domain-goals
diff --git a/src/doc/rustc-dev-guide/src/appendix/glossary.md b/src/doc/rustc-dev-guide/src/appendix/glossary.md
index a7c3236d356..1837b59e850 100644
--- a/src/doc/rustc-dev-guide/src/appendix/glossary.md
+++ b/src/doc/rustc-dev-guide/src/appendix/glossary.md
@@ -31,7 +31,6 @@ Term                                                  | Meaning
 <span id="generics">generics</span>            |  The list of generic parameters defined on an item. There are three kinds of generic parameters: Type, lifetime and const parameters.
 <span id="hir">HIR</span>                      |  The _high-level [IR](#ir)_, created by lowering and desugaring the AST. ([see more](../hir.md))
 <span id="hir-id">`HirId`</span>               |  Identifies a particular node in the HIR by combining a def-id with an "intra-definition offset". See [the HIR chapter for more](../hir.md#identifiers-in-the-hir).
-<span id="hir-map">HIR map</span>              |  The HIR map, accessible via `tcx.hir()`, allows you to quickly navigate the HIR and convert between various forms of identifiers.
 <span id="ice">ICE</span>                      |  Short for _internal compiler error_, this is when the compiler crashes.
 <span id="ich">ICH</span>                      |  Short for _incremental compilation hash_, these are used as fingerprints for things such as HIR and crate metadata, to check if changes have been made. This is useful in incremental compilation to see if part of a crate has changed and should be recompiled.
 <span id="infcx">`infcx`</span>                |  The type inference context (`InferCtxt`). (see `rustc_middle::infer`)
diff --git a/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md b/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md
index 556b3fdf8f8..513df1650c3 100644
--- a/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md
+++ b/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md
@@ -110,7 +110,7 @@ See [`compute_hir_hash`] for where the hash is actually computed.
 
 [SVH]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_data_structures/svh/struct.Svh.html
 [incremental compilation]: ../queries/incremental-compilation.md
-[`compute_hir_hash`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast_lowering/struct.LoweringContext.html#method.compute_hir_hash
+[`compute_hir_hash`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast_lowering/fn.compute_hir_hash.html
 
 ### Stable Crate Id
 
diff --git a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md
index 067e2871118..c3c1c41e3f6 100644
--- a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md
+++ b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md
@@ -63,7 +63,7 @@ cd rust
 > **NOTE**: A shallow clone limits which `git` commands can be run.
 > If you intend to work on and contribute to the compiler, it is
 > generally recommended to fully clone the repository [as shown above](#get-the-source-code),
-> or to perform a [partial clone](#shallow-clone-the-repository) instead.
+> or to perform a [partial clone](#partial-clone-the-repository) instead.
 >
 > For example, `git bisect` and `git blame` require access to the commit history,
 > so they don't work if the repository was cloned with `--depth 1`.
diff --git a/src/doc/rustc-dev-guide/src/building/optimized-build.md b/src/doc/rustc-dev-guide/src/building/optimized-build.md
index 0849464eab3..62dfaca89d2 100644
--- a/src/doc/rustc-dev-guide/src/building/optimized-build.md
+++ b/src/doc/rustc-dev-guide/src/building/optimized-build.md
@@ -109,11 +109,16 @@ like Python or LLVM.
 
 Here is an example of how can `opt-dist` be used locally (outside of CI):
 
-1. Build the tool with the following command:
+1. Enable metrics in your `bootstrap.toml` file, because `opt-dist` expects it to be enabled:
+    ```toml
+   [build]
+   metrics = true
+   ```
+2. Build the tool with the following command:
     ```bash
     ./x build tools/opt-dist
     ```
-2. Run the tool with the `local` mode and provide necessary parameters:
+3. Run the tool with the `local` mode and provide necessary parameters:
     ```bash
     ./build/host/stage0-tools-bin/opt-dist local \
       --target-triple <target> \ # select target, e.g. "x86_64-unknown-linux-gnu"
diff --git a/src/doc/rustc-dev-guide/src/building/prerequisites.md b/src/doc/rustc-dev-guide/src/building/prerequisites.md
index f49f6bb0527..6761cabac1f 100644
--- a/src/doc/rustc-dev-guide/src/building/prerequisites.md
+++ b/src/doc/rustc-dev-guide/src/building/prerequisites.md
@@ -38,4 +38,4 @@ incremental compilation ([see here][config]). This will make compilation take
 longer (especially after a rebase), but will save a ton of space from the
 incremental caches.
 
-[config]: ./how-to-build-and-run.md#create-a-configtoml
+[config]: ./how-to-build-and-run.md#create-a-bootstraptoml
diff --git a/src/doc/rustc-dev-guide/src/compiler-debugging.md b/src/doc/rustc-dev-guide/src/compiler-debugging.md
index 47f39762022..102e2020779 100644
--- a/src/doc/rustc-dev-guide/src/compiler-debugging.md
+++ b/src/doc/rustc-dev-guide/src/compiler-debugging.md
@@ -301,7 +301,8 @@ Right below you can find elaborate explainers on a selected few.
 
 Some compiler options for debugging specific features yield graphviz graphs -
 e.g. the `#[rustc_mir(borrowck_graphviz_postflow="suffix.dot")]` attribute
-dumps various borrow-checker dataflow graphs.
+on a function dumps various borrow-checker dataflow graphs in conjunction with
+`-Zdump-mir-dataflow`.
 
 These all produce `.dot` files. To view these files, install graphviz (e.g.
 `apt-get install graphviz`) and then run the following commands:
diff --git a/src/doc/rustc-dev-guide/src/const-eval.md b/src/doc/rustc-dev-guide/src/const-eval.md
index 69329a3e085..ca6a35a5e97 100644
--- a/src/doc/rustc-dev-guide/src/const-eval.md
+++ b/src/doc/rustc-dev-guide/src/const-eval.md
@@ -35,7 +35,7 @@ They're the wrappers of the `const_eval` query.
   Statics are special; all other functions do not represent statics correctly
   and have thus assertions preventing their use on statics.
 
-The `const_eval_*` functions use a [`ParamEnv`](./param_env/param_env_summary.html) of environment
+The `const_eval_*` functions use a [`ParamEnv`](./typing_parameter_envs.html) of environment
 in which the constant is evaluated (e.g. the function within which the constant is used)
 and a [`GlobalId`]. The `GlobalId` is made up of an `Instance` referring to a constant
 or static or of an `Instance` of a function and an index into the function's `Promoted` table.
diff --git a/src/doc/rustc-dev-guide/src/diagnostics.md b/src/doc/rustc-dev-guide/src/diagnostics.md
index 972309b5cd3..6f72ea902f5 100644
--- a/src/doc/rustc-dev-guide/src/diagnostics.md
+++ b/src/doc/rustc-dev-guide/src/diagnostics.md
@@ -954,9 +954,6 @@ application of these fields based on a variety of attributes when using
    `Self="std::iter::Iterator<char>"`. This is needed because `Self` is a
    keyword which cannot appear in attributes.
  - `direct`: user-specified rather than derived obligation.
- - `from_method`: usable both as boolean (whether the flag is present, like
-   `crate_local`) or matching against a particular method. Currently used
-   for `try`.
  - `from_desugaring`: usable both as boolean (whether the flag is present)
    or matching against a particular desugaring. The desugaring is identified
    with its variant name in the `DesugaringKind` enum.
diff --git a/src/doc/rustc-dev-guide/src/hir.md b/src/doc/rustc-dev-guide/src/hir.md
index 75f5a9e2045..65779f3129d 100644
--- a/src/doc/rustc-dev-guide/src/hir.md
+++ b/src/doc/rustc-dev-guide/src/hir.md
@@ -100,7 +100,7 @@ The HIR uses a bunch of different identifiers that coexist and serve different p
   a wrapper around a [`HirId`]. For more info about HIR bodies, please refer to the
   [HIR chapter][hir-bodies].
 
-These identifiers can be converted into one another through the [HIR map][map].
+These identifiers can be converted into one another through the `TyCtxt`.
 
 [`DefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html
 [`LocalDefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.LocalDefId.html
@@ -110,30 +110,24 @@ These identifiers can be converted into one another through the [HIR map][map].
 [`CrateNum`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.CrateNum.html
 [`DefIndex`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefIndex.html
 [`Body`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Body.html
-[hir-map]: ./hir.md#the-hir-map
 [hir-bodies]: ./hir.md#hir-bodies
-[map]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html
 
-## The HIR Map
+## HIR Operations
 
 Most of the time when you are working with the HIR, you will do so via
-the **HIR Map**, accessible in the tcx via [`tcx.hir()`] (and defined in
-the [`hir::map`] module). The [HIR map] contains a [number of methods] to
-convert between IDs of various kinds and to lookup data associated
-with a HIR node.
+`TyCtxt`. It contains a number of methods, defined in the `hir::map` module and
+mostly prefixed with `hir_`, to convert between IDs of various kinds and to
+lookup data associated with a HIR node.
 
-[`tcx.hir()`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir
-[`hir::map`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/index.html
-[HIR map]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html
-[number of methods]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#methods
+[`TyCtxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html
 
 For example, if you have a [`LocalDefId`], and you would like to convert it
-to a [`HirId`], you can use [`tcx.hir().local_def_id_to_hir_id(def_id)`][local_def_id_to_hir_id].
+to a [`HirId`], you can use [`tcx.local_def_id_to_hir_id(def_id)`][local_def_id_to_hir_id].
 You need a `LocalDefId`, rather than a `DefId`, since only local items have HIR nodes.
 
-[local_def_id_to_hir_id]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.local_def_id_to_hir_id
+[local_def_id_to_hir_id]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.local_def_id_to_hir_id
 
-Similarly, you can use [`tcx.hir().find(n)`][find] to lookup the node for a
+Similarly, you can use [`tcx.hir_node(n)`][hir_node] to lookup the node for a
 [`HirId`]. This returns a `Option<Node<'hir>>`, where [`Node`] is an enum
 defined in the map. By matching on this, you can find out what sort of
 node the `HirId` referred to and also get a pointer to the data
@@ -142,15 +136,16 @@ that `n` must be some HIR expression, you can do
 [`tcx.hir_expect_expr(n)`][expect_expr], which will extract and return the
 [`&hir::Expr`][Expr], panicking if `n` is not in fact an expression.
 
-[find]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.find
+[hir_node]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir_node
 [`Node`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.Node.html
 [expect_expr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.expect_expr
 [Expr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Expr.html
 
-Finally, you can use the HIR map to find the parents of nodes, via
-calls like [`tcx.hir().get_parent(n)`][get_parent].
+Finally, you can find the parents of nodes, via
+calls like [`tcx.parent_hir_node(n)`][parent_hir_node].
+
+[get_parent_item]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.parent_hir_node
 
-[get_parent]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.get_parent
 
 ## HIR Bodies
 
@@ -158,10 +153,10 @@ A [`rustc_hir::Body`] represents some kind of executable code, such as the body
 of a function/closure or the definition of a constant. Bodies are
 associated with an **owner**, which is typically some kind of item
 (e.g. an `fn()` or `const`), but could also be a closure expression
-(e.g. `|x, y| x + y`). You can use the HIR map to find the body
-associated with a given def-id ([`maybe_body_owned_by`]) or to find
-the owner of a body ([`body_owner_def_id`]).
+(e.g. `|x, y| x + y`). You can use the `TyCtxt` to find the body
+associated with a given def-id ([`hir_maybe_body_owned_by`]) or to find
+the owner of a body ([`hir_body_owner_def_id`]).
 
 [`rustc_hir::Body`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Body.html
-[`maybe_body_owned_by`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.maybe_body_owned_by
-[`body_owner_def_id`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.body_owner_def_id
+[`hir_maybe_body_owned_by`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir_maybe_body_owned_by
+[`hir_body_owner_def_id`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir_body_owner_def_id
diff --git a/src/doc/rustc-dev-guide/src/name-resolution.md b/src/doc/rustc-dev-guide/src/name-resolution.md
index 2727b8142f2..719ebce8553 100644
--- a/src/doc/rustc-dev-guide/src/name-resolution.md
+++ b/src/doc/rustc-dev-guide/src/name-resolution.md
@@ -120,9 +120,9 @@ even though they should be visible by ordinary scoping rules. An example:
 fn do_something<T: Default>(val: T) { // <- New rib in both types and values (1)
     // `val` is accessible, as is the helper function
     // `T` is accessible
-    let helper = || { // New rib on `helper` (2) and another on the block (3)
+   let helper = || { // New rib on the block (2)
         // `val` is accessible here
-    }; // End of (3)
+    }; // End of (2), new rib on `helper` (3)
     // `val` is accessible, `helper` variable shadows `helper` function
     fn helper() { // <- New rib in both types and values (4)
         // `val` is not accessible here, (4) is not transparent for locals
@@ -130,7 +130,7 @@ fn do_something<T: Default>(val: T) { // <- New rib in both types and values (1)
     } // End of (4)
     let val = T::default(); // New rib (5)
     // `val` is the variable, not the parameter here
-} // End of (5), (2) and (1)
+} // End of (5), (3) and (1)
 ```
 
 Because the rules for different namespaces are a bit different, each namespace
diff --git a/src/doc/rustc-dev-guide/src/notification-groups/fuchsia.md b/src/doc/rustc-dev-guide/src/notification-groups/fuchsia.md
new file mode 100644
index 00000000000..e3c1a7148d3
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/notification-groups/fuchsia.md
@@ -0,0 +1,12 @@
+# Fuchsia notification group
+
+**Github Label:** [O-fuchsia] <br>
+**Ping command:** `@rustbot ping fuchsia`
+
+[O-fuchsia]: https://github.com/rust-lang/rust/labels/O-fuchsia
+
+This list will be used to notify [Fuchsia][fuchsia] maintainers
+when the compiler or the standard library changes in a way that would
+break the Fuchsia integration.
+
+[fuchsia]: ../tests/ecosystem-test-jobs/fuchsia.md
diff --git a/src/doc/rustc-dev-guide/src/param_env/param_env_acquisition.md b/src/doc/rustc-dev-guide/src/param_env/param_env_acquisition.md
deleted file mode 100644
index f6cff2d6c63..00000000000
--- a/src/doc/rustc-dev-guide/src/param_env/param_env_acquisition.md
+++ /dev/null
@@ -1,43 +0,0 @@
-
-# Which `ParamEnv` do I use?
-
-When needing a [`ParamEnv`][pe] in the compiler there are a few options for obtaining one:
-- The correct env is already in scope simply use it (or pass it down the call stack to where you are).
-- The [`tcx.param_env(def_id)` query][param_env_query]
-- Use [`ParamEnv::new`][param_env_new] to construct an env with an arbitrary set of where clauses. Then call [`traits::normalize_param_env_or_error`][normalize_env_or_error] which will handle normalizing and elaborating all the where clauses in the env for you.
-- Creating an empty environment via [`ParamEnv::reveal_all`][env_reveal_all] or [`ParamEnv::empty`][env_empty]
-
-In the large majority of cases a `ParamEnv` when required already exists somewhere in scope or above in the call stack and should be passed down. A non exhaustive list of places where you might find an existing `ParamEnv`:
-- During typeck `FnCtxt` has a [`param_env` field][fnctxt_param_env]
-- When writing late lints the `LateContext` has a [`param_env` field][latectxt_param_env]
-- During well formedness checking the `WfCheckingCtxt` has a [`param_env` field][wfckctxt_param_env]
-- The `TypeChecker` used by Mir Typeck has a [`param_env` field][mirtypeck_param_env]
-- In the next-gen trait solver all `Goal`s have a [`param_env` field][goal_param_env] specifying what environment to prove the goal in
-- When editing an existing [`TypeRelation`][typerelation] if it implements `PredicateEmittingRelation` then a [`param_env` method][typerelation_param_env] will be available.
-
-Using the `param_env` query to obtain an env is generally done at the start of some kind of analysis and then passed everywhere that a `ParamEnv` is required. For example the type checker will create a `ParamEnv` for the item it is type checking and then pass it around everywhere.
-
-Creating an env from an arbitrary set of where clauses is usually unnecessary and should only be done if the environment you need does not correspond to an actual item in the source code (i.e. [`compare_method_predicate_entailment`][method_pred_entailment] as mentioned earlier).
-
-Creating an empty environment via `ParamEnv::empty` is almost always wrong. There are very few places where we actually know that the environment should be empty. One of the only places where we do actually know this is after monomorphization, however the `ParamEnv` there should be constructed via `ParamEnv::reveal_all` instead as at this point we should be able to determine the hidden type of opaque types. Codegen/Post-mono is one of the only places that should be using `ParamEnv::reveal_all`.
-
-An additional piece of complexity here is specifying the `Reveal` (see linked docs for explanation of what reveal does) used for the `ParamEnv`. When constructing a param env using the `param_env` query it will have `Reveal::UserFacing`, if `Reveal::All` is desired then the [`tcx.param_env_reveal_all_normalized`][env_reveal_all_normalized] query can be used instead.
-
-The `ParamEnv` type has a method [`ParamEnv::with_reveal_all_normalized`][with_reveal_all] which converts an existing `ParamEnv` into one with `Reveal::All` specified. Where possible the previously mentioned query should be preferred as it is more efficient.
-
-[param_env_new]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html#method.new
-[normalize_env_or_error]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/fn.normalize_param_env_or_error.html
-[fnctxt_param_env]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn_ctxt/struct.FnCtxt.html#structfield.param_env
-[latectxt_param_env]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/context/struct.LateContext.html#structfield.param_env
-[wfckctxt_param_env]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/check/wfcheck/struct.WfCheckingCtxt.html#structfield.param_env
-[goal_param_env]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/infer/canonical/ir/solve/struct.Goal.html#structfield.param_env
-[typerelation_param_env]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/infer/trait.PredicateEmittingRelation.html#tymethod.param_env
-[typerelation]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/relate/trait.TypeRelation.html
-[mirtypeck_param_env]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/type_check/struct.TypeChecker.html#structfield.param_env
-[env_reveal_all_normalized]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.param_env_reveal_all_normalized
-[with_reveal_all]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html#method.with_reveal_all_normalized
-[env_reveal_all]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html#method.reveal_all
-[env_empty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html#method.empty
-[pe]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html
-[param_env_query]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn_ctxt/struct.FnCtxt.html#structfield.param_env
-[method_pred_entailment]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/check/compare_impl_item/fn.compare_method_predicate_entailment.html
diff --git a/src/doc/rustc-dev-guide/src/param_env/param_env_construction_internals.md b/src/doc/rustc-dev-guide/src/param_env/param_env_construction_internals.md
deleted file mode 100644
index 69a262a176e..00000000000
--- a/src/doc/rustc-dev-guide/src/param_env/param_env_construction_internals.md
+++ /dev/null
@@ -1,83 +0,0 @@
-
-# How are `ParamEnv`'s constructed internally?
-
-Creating a [`ParamEnv`][pe] is more complicated than simply using the list of where clauses defined on an item as written by the user. We need to both elaborate supertraits into the env and fully normalize all aliases. This logic is handled by [`traits::normalize_param_env_or_error`][normalize_env_or_error] (even though it does not mention anything about elaboration).
-
-## Elaborating supertraits
-
-When we have a function such as `fn foo<T: Copy>()` we would like to be able to prove `T: Clone` inside of the function as the `Copy` trait has a `Clone` supertrait. Constructing a `ParamEnv` looks at all of the trait bounds in the env and explicitly adds new where clauses to the `ParamEnv` for any supertraits found on the traits.
-
-A concrete example would be the following function:
-```rust
-trait Trait: SuperTrait {}
-trait SuperTrait: SuperSuperTrait {}
-
-// `bar`'s unelaborated `ParamEnv` would be:
-// `[T: Sized, T: Copy, T: Trait]`
-fn bar<T: Copy + Trait>(a: T) {
-    requires_impl(a);
-}
-
-fn requires_impl<T: Clone + SuperSuperTrait>(a: T) {}
-```
-
-If we did not elaborate the env then the `requires_impl` call would fail to typecheck as we would not be able to prove `T: Clone` or `T: SuperSuperTrait`. In practice we elaborate the env which means that `bar`'s `ParamEnv` is actually:
-`[T: Sized, T: Copy, T: Clone, T: Trait, T: SuperTrait, T: SuperSuperTrait]`
-This allows us to prove `T: Clone` and `T: SuperSuperTrait` when type checking `bar`.
-
-The `Clone` trait has a `Sized` supertrait however we do not end up with two `T: Sized` bounds in the env (one for the supertrait and one for the implicitly added `T: Sized` bound). This is because the elaboration process (implemented via [`util::elaborate`][elaborate]) deduplicates the where clauses to avoid this.
-
-As a side effect this also means that even if no actual elaboration of supertraits takes place, the existing where clauses in the env are _also_ deduplicated. See the following example:
-```rust
-trait Trait {}
-// The unelaborated `ParamEnv` would be:
-// `[T: Sized, T: Trait, T: Trait]`
-// but after elaboration it would be:
-// `[T: Sized, T: Trait]`
-fn foo<T: Trait + Trait>() {}
-```
-
-The [next-gen trait solver][next-gen-solver] also requires this elaboration to take place.
-
-[elaborate]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/traits/util/fn.elaborate.html
-[next-gen-solver]: ../solve/trait-solving.md
-
-## Normalizing all bounds
-
-In the old trait solver the where clauses stored in `ParamEnv` are required to be fully normalized or else the trait solver will not function correctly.  A concrete example of needing to normalize the `ParamEnv` is the following:
-```rust
-trait Trait<T> {
-    type Assoc;
-}
-
-trait Other {
-    type Bar;
-}
-
-impl<T> Other for T {
-    type Bar = u32;
-}
-
-// `foo`'s unnormalized `ParamEnv` would be:
-// `[T: Sized, U: Sized, U: Trait<T::Bar>]`
-fn foo<T, U>(a: U) 
-where
-    U: Trait<<T as Other>::Bar>,
-{
-    requires_impl(a);
-}
-
-fn requires_impl<U: Trait<u32>>(_: U) {}
-```
-
-As humans we can tell that `<T as Other>::Bar` is equal to `u32` so the trait bound on `U` is equivalent to `U: Trait<u32>`. In practice trying to prove `U: Trait<u32>` in the old solver in this environment would fail as it is unable to determine that `<T as Other>::Bar` is equal to `u32`.
-
-To work around this we normalize `ParamEnv`'s after constructing them so that `foo`'s `ParamEnv` is actually: `[T: Sized, U: Sized, U: Trait<u32>]` which means the trait solver is now able to use the `U: Trait<u32>` in the `ParamEnv` to determine that the trait bound `U: Trait<u32>` holds.
-
-This workaround does not work in all cases as normalizing associated types requires a `ParamEnv` which introduces a bootstrapping problem. We need a normalized `ParamEnv` in order for normalization to give correct results, but we need to normalize to get that `ParamEnv`. Currently we normalize the `ParamEnv` once using the unnormalized param env and it tends to give okay results in practice even though there are some examples where this breaks ([example]).
-
-In the next-gen trait solver the requirement for all where clauses in the `ParamEnv` to be fully normalized is not present and so we do not normalize when constructing `ParamEnv`s.
-
-[example]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e6933265ea3e84eaa47019465739992c
-[pe]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html
-[normalize_env_or_error]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/fn.normalize_param_env_or_error.html
diff --git a/src/doc/rustc-dev-guide/src/param_env/param_env_summary.md b/src/doc/rustc-dev-guide/src/param_env/param_env_summary.md
deleted file mode 100644
index 0ff6d8fc394..00000000000
--- a/src/doc/rustc-dev-guide/src/param_env/param_env_summary.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# The `ParamEnv` type
-
-## Summary
-
-The [`ParamEnv`][pe] is used to store information about the environment that we are interacting with the type system from. For example the set of in-scope where-clauses is stored in `ParamEnv` as it differs between each item whereas the list of user written impls is not stored in the `ParamEnv` as this does not change for each item.
-
-This chapter of the dev guide covers:
-- A high level summary of what a `ParamEnv` is and what it is used for
-- Technical details about what the process of constructing a `ParamEnv` involves
-- Guidance about how to acquire a `ParamEnv` when one is required
-
-## Bundling
-
-A useful API on `ParamEnv` is the [`and`][and] method which allows bundling a value with the `ParamEnv`. The `and` method produces a [`ParamEnvAnd<T>`][pea] making it clearer that using the inner value is intended to be done in that specific environment.
-
-[and]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html#method.and
-[pe]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html
-[pea]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnvAnd.html
\ No newline at end of file
diff --git a/src/doc/rustc-dev-guide/src/param_env/param_env_what_is_it.md b/src/doc/rustc-dev-guide/src/param_env/param_env_what_is_it.md
deleted file mode 100644
index 5c2f4d59405..00000000000
--- a/src/doc/rustc-dev-guide/src/param_env/param_env_what_is_it.md
+++ /dev/null
@@ -1,59 +0,0 @@
-
-# What is a `ParamEnv`?
-
-The type system relies on information in the environment in order for it to function correctly. This information is stored in the [`ParamEnv`][pe] type and it is important to use the correct `ParamEnv` when interacting with the type system.
-
-The information represented by `ParamEnv` is a list of in-scope where-clauses, and a `Reveal` (see linked docs for more information). A `ParamEnv` typically corresponds to a specific item's where clauses, some clauses are not explicitly written bounds and instead are implicitly added in [`predicates_of`][predicates_of] such as `ConstArgHasType` or some implied bounds.
-
-A `ParamEnv` can also be created with arbitrary data that is not derived from a specific item such as in [`compare_method_predicate_entailment`][method_pred_entailment] which creates a hybrid `ParamEnv` consisting of the impl's where clauses and the trait definition's function's where clauses. In most cases `ParamEnv`s are initially created via the [`param_env` query][query] which returns a `ParamEnv` derived from the provided item's where clauses.
-
-If we have a function such as:
-```rust
-// `foo` would have a `ParamEnv` of:
-// `[T: Sized, T: Trait, <T as Trait>::Assoc: Clone]`
-fn foo<T: Trait>()
-where
-    <T as Trait>::Assoc: Clone,
-{}
-```
-If we were conceptually inside of `foo` (for example, type-checking or linting it) we would use this `ParamEnv` everywhere that we interact with the type system. This would allow things such as normalization (TODO: write a chapter about normalization and link it), evaluating generic constants, and proving where clauses/goals, to rely on `T` being sized, implementing `Trait`, etc.
-
-A more concrete example:
-```rust
-// `foo` would have a `ParamEnv` of:
-// `[T: Sized, T: Clone]`
-fn foo<T: Clone>(a: T) {
-    // when typechecking `foo` we require all the where clauses on `bar`
-    // to hold in order for it to be legal to call. This means we have to
-    // prove `T: Clone`. As we are type checking `foo` we use `foo`'s
-    // environment when trying to check that `T: Clone` holds.
-    //
-    // Trying to prove `T: Clone` with a `ParamEnv` of `[T: Sized, T: Clone]`
-    // will trivially succeed as bound we want to prove is in our environment.
-    requires_clone(a);
-}
-```
-
-Or alternatively an example that would not compile:
-```rust
-// `foo2` would have a `ParamEnv` of:
-// `[T: Sized]`
-fn foo2<T>(a: T) {
-    // When typechecking `foo2` we attempt to prove `T: Clone`.
-    // As we are type checking `foo2` we use `foo2`'s environment
-    // when trying to prove `T: Clone`.
-    //
-    // Trying to prove `T: Clone` with a `ParamEnv` of `[T: Sized]` will
-    // fail as there is nothing in the environment telling the trait solver
-    // that `T` implements `Clone` and there exists no user written impl
-    // that could apply.
-    requires_clone(a);
-}
-```
-
-It's very important to use the correct `ParamEnv` when interacting with the type system as otherwise it can lead to ICEs or things compiling when they shouldn't (or vice versa). See [#82159](https://github.com/rust-lang/rust/pull/82159) and [#82067](https://github.com/rust-lang/rust/pull/82067) as examples of PRs that changed rustc to use the correct param env to avoid ICE. Determining how to acquire the correct `ParamEnv` is explained later in this chapter.
-
-[predicates_of]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/collect/predicates_of/fn.predicates_of.html
-[method_pred_entailment]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/check/compare_impl_item/fn.compare_method_predicate_entailment.html
-[pe]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html
-[query]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.param_env
diff --git a/src/doc/rustc-dev-guide/src/rustc-driver/getting-diagnostics.md b/src/doc/rustc-dev-guide/src/rustc-driver/getting-diagnostics.md
index 1043df6ecb6..518cf4e821a 100644
--- a/src/doc/rustc-dev-guide/src/rustc-driver/getting-diagnostics.md
+++ b/src/doc/rustc-dev-guide/src/rustc-driver/getting-diagnostics.md
@@ -7,7 +7,7 @@ otherwise be printed to stderr.
 
 To get diagnostics from the compiler,
 configure [`rustc_interface::Config`] to output diagnostic to a buffer,
-and run [`TyCtxt.analysis`].
+and run [`rustc_hir_typeck::typeck`] for each item.
 
 ```rust
 {{#include ../../examples/rustc-interface-getting-diagnostics.rs}}
@@ -16,3 +16,4 @@ and run [`TyCtxt.analysis`].
 [`rustc_interface`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/index.html
 [`rustc_interface::Config`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/interface/struct.Config.html
 [`TyCtxt.analysis`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/passes/fn.analysis.html
+[`rustc_hir_typeck::typeck`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn.typeck.html
diff --git a/src/doc/rustc-dev-guide/src/rustc-driver/remarks-on-perma-unstable-features.md b/src/doc/rustc-dev-guide/src/rustc-driver/remarks-on-perma-unstable-features.md
new file mode 100644
index 00000000000..b434cfc9cf1
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/rustc-driver/remarks-on-perma-unstable-features.md
@@ -0,0 +1,54 @@
+# Remarks on perma unstable features
+
+## `rustc_private`
+
+### Overview
+
+The `rustc_private` feature allows external crates to use compiler internals.
+
+### Using `rustc-private` with Official Toolchains
+
+When using the `rustc_private` feature with official Rust toolchains distributed via rustup, you need to install two additional components:
+
+1. **`rustc-dev`**: Provides compiler libraries
+2. **`llvm-tools`**: Provides LLVM libraries required for linking
+
+#### Installation Steps
+
+Install both components using rustup:
+
+```text
+rustup component add rustc-dev llvm-tools
+```
+
+#### Common Error
+
+Without the `llvm-tools` component, you'll encounter linking errors like:
+
+```text
+error: linking with `cc` failed: exit status: 1
+  |
+  = note: rust-lld: error: unable to find library -lLLVM-{version}
+```
+
+### Using `rustc-private` with Custom Toolchains
+
+For custom-built toolchains or environments not using rustup, additional configuration is typically required:
+
+#### Requirements
+
+- LLVM libraries must be available in your system's library search paths
+- The LLVM version must match the one used to build your Rust toolchain
+
+#### Troubleshooting Steps
+
+1. **Check LLVM installation**: Verify LLVM is installed and accessible
+2. **Configure library paths**: You may need to set environment variables:
+   ```text
+   export LD_LIBRARY_PATH=/path/to/llvm/lib:$LD_LIBRARY_PATH
+   ```
+3. **Check version compatibility**: Ensure your LLVM version is compatible with your Rust toolchain
+
+### Additional Resources
+
+- [GitHub Issue #137421](https://github.com/rust-lang/rust/issues/137421): Explains that `rustc_private` linker failures often occur because `llvm-tools` is not installed
diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md
new file mode 100644
index 00000000000..169b95a7e1a
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md
@@ -0,0 +1,112 @@
+# The `rustdoc` test suite
+
+This page is specifically about the test suite named `rustdoc`.
+For other test suites used for testing rustdoc, see [Rustdoc tests](../rustdoc.md#tests).
+
+The `rustdoc` test suite is specifically used to test the HTML output of rustdoc.
+
+This is achieved by means of `htmldocck.py`, a custom checker script that leverages [XPath].
+
+[XPath]: https://en.wikipedia.org/wiki/XPath
+
+## Directives
+Directives to htmldocck are similar to those given to `compiletest` in that they take the form of `//@` comments.
+
+In addition to the directives listed here,
+`rustdoc` tests also support most
+[compiletest directives](../tests/directives.html).
+
+All `PATH`s in directives are relative to the the rustdoc output directory (`build/TARGET/test/rustdoc/TESTNAME`),
+so it is conventional to use a `#![crate_name = "foo"]` attribute to avoid
+having to write a long crate name multiple times.
+To avoid repetion, `-` can be used in any `PATH` argument to re-use the previous `PATH` argument.
+
+All arguments take the form of quoted strings
+(both single and double quotes are supported),
+with the exception of `COUNT` and the special `-` form of `PATH`.
+
+Directives are assertions that place constraints on the generated HTML.
+
+All directives (except `files`) can be negated by putting a `!` in front of their name.
+
+Similar to shell commands,
+directives can extend across multiple lines if their last char is `\`.
+In this case, the start of the next line should be `//`, with no `@`.
+
+For example, `//@ !has 'foo/struct.Bar.html'` checks that crate `foo` does not have a page for a struct named `Bar` in the crate root.
+
+### `has`
+
+Usage 1: `//@ has PATH`
+Usage 2: `//@ has PATH XPATH PATTERN`
+
+In the first form, `has` checks that a given file exists.
+
+In the second form, `has` is an alias for `matches`,
+except `PATTERN` is a whitespace-normalized[^1] string instead of a regex.
+
+### `matches`
+
+Usage: `//@ matches PATH XPATH PATTERN`
+
+Checks that the text of each element selected by `XPATH` in `PATH` matches the python-flavored regex `PATTERN`.
+
+### `matchesraw`
+
+Usage: `//@ matchesraw PATH PATTERN`
+
+Checks that the contents of the file `PATH` matches the regex `PATTERN`.
+
+### `hasraw`
+
+Usage: `//@ hasraw PATH PATTERN`
+
+Same as `matchesraw`, except `PATTERN` is a whitespace-normalized[^1] string instead of a regex.
+
+### `count`
+
+Usage: `//@ count PATH XPATH COUNT`
+
+Checks that there are exactly `COUNT` matches for `XPATH` within the file `PATH`.
+
+### `snapshot`
+
+Usage: `//@ snapshot NAME PATH XPATH`
+
+Creates a snapshot test named NAME.
+A snapshot test captures a subtree of the DOM, at the location
+determined by the XPath, and compares it to a pre-recorded value
+in a file. The file's name is the test's name with the `.rs` extension
+replaced with `.NAME.html`, where NAME is the snapshot's name.
+
+htmldocck supports the `--bless` option to accept the current subtree
+as expected, saving it to the file determined by the snapshot's name.
+compiletest's `--bless` flag is forwarded to htmldocck.
+
+### `has-dir`
+
+Usage: `//@ has-dir PATH`
+
+Checks for the existance of directory `PATH`.
+
+### `files`
+
+Usage: `//@ files PATH ENTRIES`
+
+Checks that the directory `PATH` contains exactly `ENTRIES`.
+`ENTRIES` is a python list of strings inside a quoted string,
+as if it were to be parsed by `eval`.
+(note that the list is actually parsed by `shlex.split`,
+so it cannot contain arbitrary python expressions).
+
+Example: `//@ files "foo/bar" '["index.html", "sidebar-items.js"]'`
+
+[^1]: Whitespace normalization means that all spans of consecutive whitespace are replaced with a single space.  The files themselves are also whitespace-normalized.
+
+## Limitations
+`htmldocck.py` uses the xpath implementation from the standard library.
+This leads to several limitations:
+* All `XPATH` arguments must start with `//` due to a flaw in the implemention.
+* Many XPath features (functions, axies, etc.) are not supported.
+* Only well-formed HTML can be parsed (hopefully rustdoc doesn't output mismatched tags).
+
diff --git a/src/doc/rustc-dev-guide/src/rustdoc.md b/src/doc/rustc-dev-guide/src/rustdoc.md
index 356698148e4..e36d6a388a9 100644
--- a/src/doc/rustc-dev-guide/src/rustdoc.md
+++ b/src/doc/rustc-dev-guide/src/rustdoc.md
@@ -77,29 +77,33 @@ does is call the `main()` that's in this crate's `lib.rs`, though.)
   `doctest.rs`.
 * The Markdown renderer is loaded up in `html/markdown.rs`, including functions
   for extracting doctests from a given block of Markdown.
-* The tests on the structure of rustdoc HTML output are located in `tests/rustdoc`, where
-  they're handled by the test runner of bootstrap and the supplementary script
-  `src/etc/htmldocck.py`.
 * Frontend CSS and JavaScript are stored in `html/static/`.
 
 ## Tests
 
-* All paths in this section are relative to `tests` in the rust-lang/rust repository.
-* Tests on search engine and index are located in `rustdoc-js` and `rustdoc-js-std`.
+* Tests on search engine and index are located in `tests/rustdoc-js` and `tests/rustdoc-js-std`.
   The format is specified
   [in the search guide](rustdoc-internals/search.md#testing-the-search-engine).
 * Tests on the "UI" of rustdoc (the terminal output it produces when run) are in
-  `rustdoc-ui`
+  `tests/rustdoc-ui`
 * Tests on the "GUI" of rustdoc (the HTML, JS, and CSS as rendered in a browser)
-  are in `rustdoc-gui`. These use a [NodeJS tool called
+  are in `tests/rustdoc-gui`. These use a [NodeJS tool called
   browser-UI-test](https://github.com/GuillaumeGomez/browser-UI-test/) that uses
   puppeteer to run tests in a headless browser and check rendering and
-  interactivity.
+  interactivity.  For information on how to write this form of test,
+  see [`tests/rustdoc-gui/README.md`][rustdoc-gui-readme]
+  as well as [the description of the `.goml` format][goml-script]
 * Additionally, JavaScript type annotations are written using [TypeScript-flavored JSDoc]
   comments and an external d.ts file. The code itself is plain, valid JavaScript; we only
   use tsc as a linter.
+* The tests on the structure of rustdoc HTML output are located in `tests/rustdoc`,
+  where they're handled by the test runner of bootstrap and
+  the supplementary script `src/etc/htmldocck.py`.
+  [These tests have several extra directives available to them](./rustdoc-internals/rustdoc-test-suite.md).
 
 [TypeScript-flavored JSDoc]: https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html
+[rustdoc-gui-readme]: https://github.com/rust-lang/rust/blob/master/tests/rustdoc-gui/README.md
+[goml-script]: https://github.com/GuillaumeGomez/browser-UI-test/blob/master/goml-script.md
 
 ## Constraints
 
diff --git a/src/doc/rustc-dev-guide/src/solve/opaque-types.md b/src/doc/rustc-dev-guide/src/solve/opaque-types.md
index 672aab77080..509c34a4d3a 100644
--- a/src/doc/rustc-dev-guide/src/solve/opaque-types.md
+++ b/src/doc/rustc-dev-guide/src/solve/opaque-types.md
@@ -33,7 +33,7 @@ For opaque types in the defining scope and in the implicit-negative coherence mo
 always done in two steps. Outside of the defining scope `normalizes-to` for opaques always
 returns `Err(NoSolution)`.
 
-We start by trying to to assign the expected type as a hidden type.
+We start by trying to assign the expected type as a hidden type.
 
 In the implicit-negative coherence mode, this currently always results in ambiguity without
 interacting with the opaque types storage. We could instead add allow 'defining' all opaque types,
diff --git a/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_clif.md b/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_clif.md
new file mode 100644
index 00000000000..030ddd7dff5
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_clif.md
@@ -0,0 +1,3 @@
+# Cranelift codegen backend tests
+
+TODO: please add some more information to this page.
diff --git a/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md b/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md
new file mode 100644
index 00000000000..4caf4c0e0ee
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md
@@ -0,0 +1,3 @@
+# GCC codegen backend tests
+
+TODO: please add some more information to this page.
diff --git a/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/intro.md b/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/intro.md
new file mode 100644
index 00000000000..6bf46ddcd21
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/intro.md
@@ -0,0 +1,13 @@
+# Codegen backend testing
+
+See also the [Code generation](../../backend/codegen.md) chapter.
+
+In addition to the primary LLVM codegen backend, the rust-lang/rust CI also runs tests of the [cranelift][cg_clif] and [GCC][cg_gcc] codegen backends in certain test jobs.
+
+For more details on the tests involved, see:
+
+- [Cranelift codegen backend tests](./cg_clif.md)
+- [GCC codegen backend tests](./cg_gcc.md)
+
+[cg_clif]: https://github.com/rust-lang/rustc_codegen_cranelift
+[cg_gcc]: https://github.com/rust-lang/rustc_codegen_gcc
diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md
index 81aa35f1a46..0aad8be982f 100644
--- a/src/doc/rustc-dev-guide/src/tests/directives.md
+++ b/src/doc/rustc-dev-guide/src/tests/directives.md
@@ -6,7 +6,8 @@
 FIXME(jieyouxu) completely revise this chapter.
 -->
 
-Directives are special comments that tell compiletest how to build and interpret a test. They must appear before the Rust source in the test. They may also appear in `rmake.rs` [run-make tests](compiletest.md#run-make-tests).
+Directives are special comments that tell compiletest how to build and interpret a test.
+They may also appear in `rmake.rs` [run-make tests](compiletest.md#run-make-tests).
 
 They are normally put after the short comment that explains the point of this
 test. Compiletest test suites use `//@` to signal that a comment is a directive.
@@ -100,6 +101,7 @@ for more details.
 | `normalize-stdout`                | Normalize actual stdout with a rule `"<raw>" -> "<normalized>"` before comparing against snapshot                        | `ui`, `incremental`                          | `"<RAW>" -> "<NORMALIZED>"`, `<RAW>`/`<NORMALIZED>` is regex capture and replace syntax |
 | `dont-check-compiler-stderr`      | Don't check actual compiler stderr vs stderr snapshot                                                                    | `ui`                                         | N/A                                                                                     |
 | `dont-check-compiler-stdout`      | Don't check actual compiler stdout vs stdout snapshot                                                                    | `ui`                                         | N/A                                                                                     |
+| `dont-require-annotations`        | Don't require line annotations for the given diagnostic kind (`//~ KIND`) to be exhaustive                               | `ui`, `incremental`                          | `ERROR`, `WARN`, `NOTE`, `HELP`, `SUGGESTION`                                           |
 | `run-rustfix`                     | Apply all suggestions via `rustfix`, snapshot fixed output, and check fixed output builds                                | `ui`                                         | N/A                                                                                     |
 | `rustfix-only-machine-applicable` | `run-rustfix` but only machine-applicable suggestions                                                                    | `ui`                                         | N/A                                                                                     |
 | `exec-env`                        | Env var to set when executing a test                                                                                     | `ui`, `crashes`                              | `<KEY>=<VALUE>`                                                                         |
@@ -190,8 +192,13 @@ settings:
   specified atomic widths, e.g. the test with `//@ needs-target-has-atomic: 8,
   16, ptr` will only run if it supports the comma-separated list of atomic
   widths.
-- `needs-dynamic-linking` - ignores if target does not support dynamic linking
+- `needs-dynamic-linking` — ignores if target does not support dynamic linking
   (which is orthogonal to it being unable to create `dylib` and `cdylib` crate types)
+- `needs-crate-type` — ignores if target platform does not support one or more
+  of the comma-delimited list of specified crate types. For example,
+  `//@ needs-crate-type: cdylib, proc-macro` will cause the test to be ignored
+  on `wasm32-unknown-unknown` target because the target does not support the
+  `proc-macro` crate type.
 
 The following directives will check LLVM support:
 
@@ -228,14 +235,14 @@ ignoring debuggers.
 
 ### Affecting how tests are built
 
-| Directive           | Explanation                                                                                  | Supported test suites     | Possible values                                                              |
-|---------------------|----------------------------------------------------------------------------------------------|---------------------------|------------------------------------------------------------------------------|
-| `compile-flags`     | Flags passed to `rustc` when building the test or aux file                                   | All except for `run-make` | Any valid `rustc` flags, e.g. `-Awarnings -Dfoo`. Cannot be `-Cincremental`. |
-| `edition`           | Alias for `compile-flags: --edition=xxx`                                                     | All except for `run-make` | Any valid `--edition` value                                                  |
-| `rustc-env`         | Env var to set when running `rustc`                                                          | All except for `run-make` | `<KEY>=<VALUE>`                                                              |
-| `unset-rustc-env`   | Env var to unset when running `rustc`                                                        | All except for `run-make` | Any env var name                                                             |
-| `incremental`       | Proper incremental support for tests outside of incremental test suite                       | `ui`, `crashes`           | N/A                                                                          |
-| `no-prefer-dynamic` | Don't use `-C prefer-dynamic`, don't build as a dylib via a `--crate-type=dylib` preset flag | `ui`, `crashes`           | N/A                                                                          |
+| Directive           | Explanation                                                                                  | Supported test suites     | Possible values                                                                            |
+|---------------------|----------------------------------------------------------------------------------------------|---------------------------|--------------------------------------------------------------------------------------------|
+| `compile-flags`     | Flags passed to `rustc` when building the test or aux file                                   | All except for `run-make` | Any valid `rustc` flags, e.g. `-Awarnings -Dfoo`. Cannot be `-Cincremental` or `--edition` |
+| `edition`           | The edition used to build the test                                                           | All except for `run-make` | Any valid `--edition` value                                                                |
+| `rustc-env`         | Env var to set when running `rustc`                                                          | All except for `run-make` | `<KEY>=<VALUE>`                                                                            |
+| `unset-rustc-env`   | Env var to unset when running `rustc`                                                        | All except for `run-make` | Any env var name                                                                           |
+| `incremental`       | Proper incremental support for tests outside of incremental test suite                       | `ui`, `crashes`           | N/A                                                                                        |
+| `no-prefer-dynamic` | Don't use `-C prefer-dynamic`, don't build as a dylib via a `--crate-type=dylib` preset flag | `ui`, `crashes`           | N/A                                                                                        |
 
 <div class="warning">
 Tests (outside of `run-make`) that want to use incremental tests not in the
diff --git a/src/doc/rustc-dev-guide/src/tests/fuchsia.md b/src/doc/rustc-dev-guide/src/tests/ecosystem-test-jobs/fuchsia.md
index e96290b9215..b19d94d6ff7 100644
--- a/src/doc/rustc-dev-guide/src/tests/fuchsia.md
+++ b/src/doc/rustc-dev-guide/src/tests/ecosystem-test-jobs/fuchsia.md
@@ -4,6 +4,14 @@
 million lines of Rust code.[^loc] It has caught a large number of [regressions]
 in the past and was subsequently included in CI.
 
+## What to do if the Fuchsia job breaks?
+
+Please contact the [fuchsia][fuchsia-ping] ping group and ask them for help.
+
+```text
+@rustbot ping fuchsia
+```
+
 ## Building Fuchsia in CI
 
 Fuchsia builds as part of the suite of bors tests that run before a pull request
@@ -32,7 +40,7 @@ using your local Rust toolchain.
 src/ci/docker/run.sh x86_64-fuchsia
 ```
 
-See the [Testing with Docker](docker.md) chapter for more details on how to run
+See the [Testing with Docker](../docker.md) chapter for more details on how to run
 and debug jobs with Docker.
 
 Note that a Fuchsia checkout is *large* – as of this writing, a checkout and
@@ -162,6 +170,7 @@ rustc book][platform-support].
 [`public_configs`]: https://gn.googlesource.com/gn/+/main/docs/reference.md#var_public_configs
 [`//build/config:compiler`]: https://cs.opensource.google/fuchsia/fuchsia/+/main:build/config/BUILD.gn;l=121;drc=c26c473bef93b33117ae417893118907a026fec7
 [build system]: https://fuchsia.dev/fuchsia-src/development/build/build_system
+[fuchsia-ping]: ../../notification-groups/fuchsia.md
 
 [^loc]: As of June 2024, Fuchsia had about 2 million lines of first-party Rust
 code and a roughly equal amount of third-party code, as counted by tokei
diff --git a/src/doc/rustc-dev-guide/src/tests/rust-for-linux.md b/src/doc/rustc-dev-guide/src/tests/ecosystem-test-jobs/rust-for-linux.md
index c674d1575b7..d549ec6fca5 100644
--- a/src/doc/rustc-dev-guide/src/tests/rust-for-linux.md
+++ b/src/doc/rustc-dev-guide/src/tests/ecosystem-test-jobs/rust-for-linux.md
@@ -3,26 +3,7 @@
 [Rust for Linux](https://rust-for-linux.com/) (RfL) is an effort for adding
 support for the Rust programming language into the Linux kernel.
 
-## Building Rust for Linux in CI
-
-Rust for Linux builds as part of the suite of bors tests that run before a pull
-request is merged.
-
-The workflow builds a stage1 sysroot of the Rust compiler, downloads the Linux
-kernel, and tries to compile several Rust for Linux drivers and examples using
-this sysroot. RfL uses several unstable compiler/language features, therefore
-this workflow notifies us if a given compiler change would break it.
-
-If you are worried that a pull request might break the Rust for Linux builder
-and want to test it out before submitting it to the bors queue, simply add this
-line to your PR description:
-
-> try-job: x86_64-rust-for-linux
-
-Then when you `@bors try` it will pick the job that builds the Rust for Linux
-integration.
-
-## What to do in case of failure
+## What to do if the Rust for Linux job breaks?
 
 If a PR breaks the Rust for Linux CI job, then:
 
@@ -48,4 +29,23 @@ ping group to ask for help:
 @rustbot ping rfl
 ```
 
-[rfl-ping]: ../notification-groups/rust-for-linux.md
+## Building Rust for Linux in CI
+
+Rust for Linux builds as part of the suite of bors tests that run before a pull
+request is merged.
+
+The workflow builds a stage1 sysroot of the Rust compiler, downloads the Linux
+kernel, and tries to compile several Rust for Linux drivers and examples using
+this sysroot. RfL uses several unstable compiler/language features, therefore
+this workflow notifies us if a given compiler change would break it.
+
+If you are worried that a pull request might break the Rust for Linux builder
+and want to test it out before submitting it to the bors queue, simply add this
+line to your PR description:
+
+> try-job: x86_64-rust-for-linux
+
+Then when you `@bors try` it will pick the job that builds the Rust for Linux
+integration.
+
+[rfl-ping]: ../../notification-groups/rust-for-linux.md
diff --git a/src/doc/rustc-dev-guide/src/tests/ecosystem.md b/src/doc/rustc-dev-guide/src/tests/ecosystem.md
index 08360140425..f4b93492e00 100644
--- a/src/doc/rustc-dev-guide/src/tests/ecosystem.md
+++ b/src/doc/rustc-dev-guide/src/tests/ecosystem.md
@@ -24,5 +24,5 @@ there aren't any significant regressions.
 We have CI jobs that build large open-source Rust projects that are used as
 regression tests in CI. Our integration jobs build the following projects:
 
-- [Fuchsia](fuchsia.md)
-- [Rust for Linux](rust-for-linux.md)
+- [Fuchsia](./ecosystem-test-jobs/fuchsia.md)
+- [Rust for Linux](./ecosystem-test-jobs/rust-for-linux.md)
diff --git a/src/doc/rustc-dev-guide/src/tests/intro.md b/src/doc/rustc-dev-guide/src/tests/intro.md
index ba44a969bf9..7bf30b106b4 100644
--- a/src/doc/rustc-dev-guide/src/tests/intro.md
+++ b/src/doc/rustc-dev-guide/src/tests/intro.md
@@ -38,7 +38,7 @@ directory, and `x` will essentially run `cargo test` on that package.
 Examples:
 
 | Command                                   | Description                           |
-| ----------------------------------------- | ------------------------------------- |
+|-------------------------------------------|---------------------------------------|
 | `./x test library/std`                    | Runs tests on `std` only              |
 | `./x test library/core`                   | Runs tests on `core` only             |
 | `./x test compiler/rustc_data_structures` | Runs tests on `rustc_data_structures` |
@@ -86,7 +86,7 @@ above.
 Examples:
 
 | Command                 | Description                                                        |
-| ----------------------- | ------------------------------------------------------------------ |
+|-------------------------|--------------------------------------------------------------------|
 | `./x fmt --check`       | Checks formatting and exits with an error if formatting is needed. |
 | `./x fmt`               | Runs rustfmt across the entire codebase.                           |
 | `./x test tidy --bless` | First runs rustfmt to format the codebase, then runs tidy checks.  |
@@ -155,6 +155,10 @@ chapter](ecosystem.md) for more details.
 A separate infrastructure is used for testing and tracking performance of the
 compiler. See the [Performance testing chapter](perf.md) for more details.
 
+### Codegen backend testing
+
+See [Codegen backend testing](./codegen-backend-tests/intro.md).
+
 ## Miscellaneous information
 
 There are some other useful testing-related info at [Misc info](misc.md).
diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md
index 6f412a7a60e..3243a3535ac 100644
--- a/src/doc/rustc-dev-guide/src/tests/ui.md
+++ b/src/doc/rustc-dev-guide/src/tests/ui.md
@@ -303,8 +303,7 @@ It should be preferred to using `error-pattern`, which is imprecise and non-exha
 ### `error-pattern`
 
 The `error-pattern` [directive](directives.md) can be used for runtime messages, which don't
-have a specific span, or for compile time messages if imprecise matching is required due to
-multi-line platform specific diagnostics.
+have a specific span, or in exceptional cases for compile time messages.
 
 Let's think about this test:
 
@@ -318,7 +317,7 @@ fn main() {
 ```
 
 We want to ensure this shows "index out of bounds" but we cannot use the `ERROR`
-annotation since the error doesn't have any span. Then it's time to use the
+annotation since the runtime error doesn't have any span. Then it's time to use the
 `error-pattern` directive:
 
 ```rust,ignore
@@ -331,28 +330,51 @@ fn main() {
 }
 ```
 
-But for strict testing, try to use the `ERROR` annotation as much as possible,
-including `//~?` annotations for diagnostics without span.
-For compile time diagnostics `error-pattern` should very rarely be necessary.
+Use of `error-pattern` is not recommended in general.
 
-Per-line annotations (`//~`) are still checked in tests using `error-pattern`,
-to opt out of these checks in exceptional cases use `//@ compile-flags: --error-format=human`.
+For strict testing of compile time output, try to use the line annotations `//~` as much as
+possible, including `//~?` annotations for diagnostics without span.
 
-### Error levels
+If the compile time output is target dependent or too verbose, use directive
+`//@ dont-require-annotations: <diagnostic-kind>` to make the line annotation checking
+non-exhaustive, some of the compiler messages can stay uncovered by annotations in this mode.
 
-The error levels that you can have are:
+For checking runtime output `//@ check-run-results` may be preferable.
+
+Only use `error-pattern` if none of the above works.
+
+Line annotations `//~` are still checked in tests using `error-pattern`.
+In exceptional cases use `//@ compile-flags: --error-format=human` to opt out of these checks.
+
+### Diagnostic kinds (error levels)
+
+The diagnostic kinds that you can have are:
 
 - `ERROR`
-- `WARN` or `WARNING`
+- `WARN` (or `WARNING`)
 - `NOTE`
-- `HELP` and `SUGGESTION`
-
-You are allowed to not include a level, but you should include it at least for
-the primary message.
+- `HELP`
+- `SUGGESTION`
 
-The `SUGGESTION` level is used for specifying what the expected replacement text
+The `SUGGESTION` kind is used for specifying what the expected replacement text
 should be for a diagnostic suggestion.
 
+`ERROR` and `WARN` kinds are required to be exhaustively covered by line annotations
+`//~` by default.
+
+Other kinds only need to be line-annotated if at least one annotation of that kind appears
+in the test file. For example, one `//~ NOTE` will also require all other `//~ NOTE`s in the file
+to be written out explicitly.
+
+Use directive `//@ dont-require-annotations` to opt out of exhaustive annotations.
+E.g. use `//@ dont-require-annotations: NOTE` to annotate notes selectively.
+Avoid using this directive for `ERROR`s and `WARN`ings, unless there's a serious reason, like
+target-dependent compiler output.
+
+Missing diagnostic kinds (`//~ message`) are currently accepted, but are being phased away.
+They will match any compiler output kind, but will not force exhaustive annotations for that kind.
+Prefer explicit kind and `//@ dont-require-annotations` to achieve the same effect.
+
 UI tests use the `-A unused` flag by default to ignore all unused warnings, as
 unused warnings are usually not the focus of a test. However, simple code
 samples often have unused warnings. If the test is specifically testing an
@@ -451,6 +473,14 @@ reasons, including:
    can alert the developer so they know that the associated issue has been fixed
    and can possibly be closed.
 
+This directive takes comma-separated issue numbers as arguments, or `"unknown"`:
+
+- `//@ known-bug: #123, #456` (when the issues are on rust-lang/rust)
+- `//@ known-bug: rust-lang/chalk#123456`
+  (allows arbitrary text before the `#`, which is useful when the issue is on another repo)
+- `//@ known-bug: unknown`
+  (when there is no known issue yet; preferrably open one if it does not already exist)
+
 Do not include [error annotations](#error-annotations) in a test with
 `known-bug`. The test should still include other normal directives and
 stdout/stderr files.
diff --git a/src/doc/rustc-dev-guide/src/traits/caching.md b/src/doc/rustc-dev-guide/src/traits/caching.md
index a9f20969b57..c44722a1d9a 100644
--- a/src/doc/rustc-dev-guide/src/traits/caching.md
+++ b/src/doc/rustc-dev-guide/src/traits/caching.md
@@ -61,7 +61,7 @@ to be pretty clearly safe and also still retains a very high hit rate
 **TODO**: it looks like `pick_candidate_cache` no longer exists. In
 general, is this section still accurate at all?
 
-[`ParamEnv`]: ../param_env/param_env_summary.html
+[`ParamEnv`]: ../typing_parameter_envs.html
 [`tcx`]: ../ty.html
 [#18290]: https://github.com/rust-lang/rust/issues/18290
 [#22019]: https://github.com/rust-lang/rust/issues/22019
diff --git a/src/doc/rustc-dev-guide/src/traits/resolution.md b/src/doc/rustc-dev-guide/src/traits/resolution.md
index 26eb7245886..c62b0593694 100644
--- a/src/doc/rustc-dev-guide/src/traits/resolution.md
+++ b/src/doc/rustc-dev-guide/src/traits/resolution.md
@@ -183,7 +183,7 @@ in that list. If so, it is considered satisfied. More precisely, we
 want to check whether there is a where-clause obligation that is for
 the same trait (or some subtrait) and which can match against the obligation.
 
-[parameter environment]: ../param_env/param_env_summary.html
+[parameter environment]: ../typing_parameter_envs.html
 
 Consider this simple example:
 
diff --git a/src/doc/rustc-dev-guide/src/ty_module/binders.md b/src/doc/rustc-dev-guide/src/ty_module/binders.md
index defb7cde514..71157eca9b1 100644
--- a/src/doc/rustc-dev-guide/src/ty_module/binders.md
+++ b/src/doc/rustc-dev-guide/src/ty_module/binders.md
@@ -40,7 +40,7 @@ We did not always explicitly track the set of bound vars introduced by each `Bin
 ```
 Binder(
     fn(&'^1_0 &'^1 T/#0),
-    &[BoundVariarbleKind::Region(...)],
+    &[BoundVariableKind::Region(...)],
 )
 ```
 This would cause all kinds of issues as the region `'^1_0` refers to a binder at a higher level than the outermost binder i.e. it is an escaping bound var. The `'^1` region (also writeable as `'^0_1`) is also ill formed as the binder it refers to does not introduce a second parameter. Modern day rustc will ICE when constructing this binder due to both of those regions, in the past we would have simply allowed this to work and then ran into issues in other parts of the codebase. 
diff --git a/src/doc/rustc-dev-guide/src/typing_parameter_envs.md b/src/doc/rustc-dev-guide/src/typing_parameter_envs.md
new file mode 100644
index 00000000000..757296d1f65
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/typing_parameter_envs.md
@@ -0,0 +1,206 @@
+# Typing/Parameter Environments
+
+<!-- toc -->
+
+## Typing Environments
+
+When interacting with the type system there are a few variables to consider that can affect the results of trait solving. The the set of in-scope where clauses, and what phase of the compiler type system operations are being performed in (the [`ParamEnv`][penv] and [`TypingMode`][tmode] structs respectively).
+
+When an environment to perform type system operations in has not yet been created, the [`TypingEnv`][tenv] can be used to bundle all of the external context required into a single type.
+
+Once a context to perform type system operations in has been created (e.g. an [`ObligationCtxt`][ocx] or [`FnCtxt`][fnctxt]) a `TypingEnv` is typically not stored anywhere as only the `TypingMode` is a property of the whole environment, whereas different `ParamEnv`s can be used on a per-goal basis.
+
+[ocx]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/struct.ObligationCtxt.html
+[fnctxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn_ctxt/struct.FnCtxt.html
+
+## Parameter Environemnts
+
+### What is a `ParamEnv`
+
+The [`ParamEnv`][penv] is a list of in-scope where-clauses, it typically corresponds to a specific item's where clauses. Some clauses are not explicitly written but are instead are implicitly added in the [`predicates_of`][predicates_of] query, such as `ConstArgHasType` or (some) implied bounds.
+
+In most cases `ParamEnv`s are initially created via the [`param_env` query][query] which returns a `ParamEnv` derived from the provided item's where clauses. A `ParamEnv` can also be created with arbitrary sets of clauses that are not derived from a specific item, such as in [`compare_method_predicate_entailment`][method_pred_entailment] where we create a hybrid `ParamEnv` consisting of the impl's where clauses and the trait definition's function's where clauses.
+
+---
+
+If we have a function such as:
+```rust
+// `foo` would have a `ParamEnv` of:
+// `[T: Sized, T: Trait, <T as Trait>::Assoc: Clone]`
+fn foo<T: Trait>()
+where
+    <T as Trait>::Assoc: Clone,
+{}
+```
+If we were conceptually inside of `foo` (for example, type-checking or linting it) we would use this `ParamEnv` everywhere that we interact with the type system. This would allow things such as normalization (TODO: write a chapter about normalization and link it), evaluating generic constants, and proving where clauses/goals, to rely on `T` being sized, implementing `Trait`, etc.
+
+A more concrete example:
+```rust
+// `foo` would have a `ParamEnv` of:
+// `[T: Sized, T: Clone]`
+fn foo<T: Clone>(a: T) {
+    // when typechecking `foo` we require all the where clauses on `requires_clone`
+    // to hold in order for it to be legal to call. This means we have to
+    // prove `T: Clone`. As we are type checking `foo` we use `foo`'s
+    // environment when trying to check that `T: Clone` holds.
+    //
+    // Trying to prove `T: Clone` with a `ParamEnv` of `[T: Sized, T: Clone]`
+    // will trivially succeed as bound we want to prove is in our environment.
+    requires_clone(a);
+}
+```
+
+Or alternatively an example that would not compile:
+```rust
+// `foo2` would have a `ParamEnv` of:
+// `[T: Sized]`
+fn foo2<T>(a: T) {
+    // When typechecking `foo2` we attempt to prove `T: Clone`.
+    // As we are type checking `foo2` we use `foo2`'s environment
+    // when trying to prove `T: Clone`.
+    //
+    // Trying to prove `T: Clone` with a `ParamEnv` of `[T: Sized]` will
+    // fail as there is nothing in the environment telling the trait solver
+    // that `T` implements `Clone` and there exists no user written impl
+    // that could apply.
+    requires_clone(a);
+}
+```
+
+[predicates_of]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/collect/predicates_of/fn.predicates_of.html
+[method_pred_entailment]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/check/compare_impl_item/fn.compare_method_predicate_entailment.html
+[query]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.param_env
+
+### Acquiring a `ParamEnv`
+
+Using the wrong [`ParamEnv`][penv] when interacting with the type system can lead to ICEs, illformed programs compiling, or erroing when we shouldn't. See [#82159](https://github.com/rust-lang/rust/pull/82159) and [#82067](https://github.com/rust-lang/rust/pull/82067) as examples of PRs that modified the compiler to use the correct param env and in the process fixed ICEs.
+
+In the large majority of cases, when a `ParamEnv` is required it either already exists somewhere in scope, or above in the call stack and should be passed down. A non exhaustive list of places where you might find an existing `ParamEnv`:
+- During typeck `FnCtxt` has a [`param_env` field][fnctxt_param_env]
+- When writing late lints the `LateContext` has a [`param_env` field][latectxt_param_env]
+- During well formedness checking the `WfCheckingCtxt` has a [`param_env` field][wfckctxt_param_env]
+- The `TypeChecker` used for MIR Typeck has a [`param_env` field][mirtypeck_param_env]
+- In the next-gen trait solver all `Goal`s have a [`param_env` field][goal_param_env] specifying what environment to prove the goal in
+- When editing an existing [`TypeRelation`][typerelation] if it implements [`PredicateEmittingRelation`][predicate_emitting_relation] then a [`param_env` method][typerelation_param_env] will be available.
+
+If you aren't sure if there's a `ParamEnv` in scope somewhere that can be used it can be worth opening a thread in the [`#t-compiler/help`][compiler_help] zulip stream where someone may be able to point out where a `ParamEnv` can be acquired from.
+
+Manually constructing a `ParamEnv` is typically only needed at the start of some kind of top level analysis (e.g. hir typeck or borrow checking). In such cases there are three ways it can be done:
+- Calling the [`tcx.param_env(def_id)` query][param_env_query] which returns the environment associated with a given definition.
+- Creating an empty environment with [`ParamEnv::empty`][env_empty].
+- Using [`ParamEnv::new`][param_env_new] to construct an env with an arbitrary set of where clauses. Then calling [`traits::normalize_param_env_or_error`][normalize_env_or_error] to handle normalizing and elaborating all the where clauses in the env.
+
+Using the `param_env` query is by far the most common way to construct a `ParamEnv` as most of the time the compiler is performing an analysis as part of some specific definition.
+
+Creating an empty environment with `ParamEnv::empty` is typically only done either in codegen (indirectly via [`TypingEnv::fully_monomorphized`][tenv_mono]), or as part of some analysis that do not expect to ever encounter generic parameters (e.g. various parts of coherence/orphan check).
+
+Creating an env from an arbitrary set of where clauses is usually unnecessary and should only be done if the environment you need does not correspond to an actual item in the source code (e.g. [`compare_method_predicate_entailment`][method_pred_entailment]).
+
+[param_env_new]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html#method.new
+[normalize_env_or_error]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/fn.normalize_param_env_or_error.html
+[fnctxt_param_env]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn_ctxt/struct.FnCtxt.html#structfield.param_env
+[latectxt_param_env]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/context/struct.LateContext.html#structfield.param_env
+[wfckctxt_param_env]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/check/wfcheck/struct.WfCheckingCtxt.html#structfield.param_env
+[goal_param_env]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/infer/canonical/ir/solve/struct.Goal.html#structfield.param_env
+[typerelation_param_env]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/infer/trait.PredicateEmittingRelation.html#tymethod.param_env
+[typerelation]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/relate/trait.TypeRelation.html
+[mirtypeck_param_env]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/type_check/struct.TypeChecker.html#structfield.param_env
+[env_empty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html#method.empty
+[param_env_query]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn_ctxt/struct.FnCtxt.html#structfield.param_env
+[method_pred_entailment]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/check/compare_impl_item/fn.compare_method_predicate_entailment.html
+[predicate_emitting_relation]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/relate/combine/trait.PredicateEmittingRelation.html
+[tenv_mono]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypingEnv.html#method.fully_monomorphized
+[compiler_help]: https://rust-lang.zulipchat.com/#narrow/channel/182449-t-compiler.2Fhelp
+
+### How are `ParamEnv`s constructed
+
+Creating a [`ParamEnv`][pe] is more complicated than simply using the list of where clauses defined on an item as written by the user. We need to both elaborate supertraits into the env and fully normalize all aliases. This logic is handled by [`traits::normalize_param_env_or_error`][normalize_env_or_error] (even though it does not mention anything about elaboration).
+
+#### Elaborating supertraits
+
+When we have a function such as `fn foo<T: Copy>()` we would like to be able to prove `T: Clone` inside of the function as the `Copy` trait has a `Clone` supertrait. Constructing a `ParamEnv` looks at all of the trait bounds in the env and explicitly adds new where clauses to the `ParamEnv` for any supertraits found on the traits.
+
+A concrete example would be the following function:
+```rust
+trait Trait: SuperTrait {}
+trait SuperTrait: SuperSuperTrait {}
+
+// `bar`'s unelaborated `ParamEnv` would be:
+// `[T: Sized, T: Copy, T: Trait]`
+fn bar<T: Copy + Trait>(a: T) {
+    requires_impl(a);
+}
+
+fn requires_impl<T: Clone + SuperSuperTrait>(a: T) {}
+```
+
+If we did not elaborate the env then the `requires_impl` call would fail to typecheck as we would not be able to prove `T: Clone` or `T: SuperSuperTrait`. In practice we elaborate the env which means that `bar`'s `ParamEnv` is actually:
+`[T: Sized, T: Copy, T: Clone, T: Trait, T: SuperTrait, T: SuperSuperTrait]`
+This allows us to prove `T: Clone` and `T: SuperSuperTrait` when type checking `bar`.
+
+The `Clone` trait has a `Sized` supertrait however we do not end up with two `T: Sized` bounds in the env (one for the supertrait and one for the implicitly added `T: Sized` bound) as the elaboration process (implemented via [`util::elaborate`][elaborate]) deduplicates where clauses.
+
+A side effect of this is that even if no actual elaboration of supertraits takes place, the existing where clauses in the env are _also_ deduplicated. See the following example:
+```rust
+trait Trait {}
+// The unelaborated `ParamEnv` would be:
+// `[T: Sized, T: Trait, T: Trait]`
+// but after elaboration it would be:
+// `[T: Sized, T: Trait]`
+fn foo<T: Trait + Trait>() {}
+```
+
+The [next-gen trait solver][next-gen-solver] also requires this elaboration to take place.
+
+[elaborate]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/traits/util/fn.elaborate.html
+[next-gen-solver]: ./solve/trait-solving.md
+
+#### Normalizing all bounds
+
+In the old trait solver the where clauses stored in `ParamEnv` are required to be fully normalized as otherwise the trait solver will not function correctly. A concrete example of needing to normalize the `ParamEnv` is the following:
+```rust
+trait Trait<T> {
+    type Assoc;
+}
+
+trait Other {
+    type Bar;
+}
+
+impl<T> Other for T {
+    type Bar = u32;
+}
+
+// `foo`'s unnormalized `ParamEnv` would be:
+// `[T: Sized, U: Sized, U: Trait<T::Bar>]`
+fn foo<T, U>(a: U) 
+where
+    U: Trait<<T as Other>::Bar>,
+{
+    requires_impl(a);
+}
+
+fn requires_impl<U: Trait<u32>>(_: U) {}
+```
+
+As humans we can tell that `<T as Other>::Bar` is equal to `u32` so the trait bound on `U` is equivalent to `U: Trait<u32>`. In practice trying to prove `U: Trait<u32>` in the old solver in this environment would fail as it is unable to determine that `<T as Other>::Bar` is equal to `u32`.
+
+To work around this we normalize `ParamEnv`'s after constructing them so that `foo`'s `ParamEnv` is actually: `[T: Sized, U: Sized, U: Trait<u32>]` which means the trait solver is now able to use the `U: Trait<u32>` in the `ParamEnv` to determine that the trait bound `U: Trait<u32>` holds.
+
+This workaround does not work in all cases as normalizing associated types requires a `ParamEnv` which introduces a bootstrapping problem. We need a normalized `ParamEnv` in order for normalization to give correct results, but we need to normalize to get that `ParamEnv`. Currently we normalize the `ParamEnv` once using the unnormalized param env and it tends to give okay results in practice even though there are some examples where this breaks ([example]).
+
+In the next-gen trait solver the requirement for all where clauses in the `ParamEnv` to be fully normalized is not present and so we do not normalize when constructing `ParamEnv`s.
+
+[example]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e6933265ea3e84eaa47019465739992c
+[pe]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html
+[normalize_env_or_error]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/fn.normalize_param_env_or_error.html
+
+## Typing Modes
+
+Depending on what context we are performing type system operations in, different behaviour may be required. For example during coherence there are stronger requirements about when we can consider goals to not hold or when we can consider types to be unequal.
+
+Tracking which "phase" of the compiler type system operations are being performed in is done by the [`TypingMode`][tenv] enum. The documentation on the `TypingMode` enum is quite good so instead of repeating it here verbatim we would recommend reading the API documentation directly.
+
+[penv]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html
+[tenv]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/infer_ctxt/enum.TypingMode.html
+[tmode]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.TypingMode.html
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index e1ba27c07da..cf41f5b86a8 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -78,6 +78,7 @@
     - [illumos](platform-support/illumos.md)
     - [loongarch\*-unknown-linux-\*](platform-support/loongarch-linux.md)
     - [loongarch\*-unknown-none\*](platform-support/loongarch-none.md)
+    - [\*-lynxos178-\*](platform-support/lynxos178.md)
     - [m68k-unknown-linux-gnu](platform-support/m68k-unknown-linux-gnu.md)
     - [m68k-unknown-none-elf](platform-support/m68k-unknown-none-elf.md)
     - [mips64-openwrt-linux-musl](platform-support/mips64-openwrt-linux-musl.md)
@@ -103,7 +104,6 @@
     - [s390x-unknown-linux-musl](platform-support/s390x-unknown-linux-musl.md)
     - [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md)
     - [solaris](platform-support/solaris.md)
-    - [\*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md)
     - [\*-nto-qnx-\*](platform-support/nto-qnx.md)
     - [\*-unikraft-linux-musl](platform-support/unikraft-linux-musl.md)
     - [\*-unknown-hermit](platform-support/hermit.md)
@@ -122,6 +122,8 @@
     - [wasm32-unknown-unknown](platform-support/wasm32-unknown-unknown.md)
     - [wasm32v1-none](platform-support/wasm32v1-none.md)
     - [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md)
+    - [windows-gnu](platform-support/windows-gnu.md)
+    - [windows-gnullvm](platform-support/windows-gnullvm.md)
     - [\*-win7-windows-gnu](platform-support/win7-windows-gnu.md)
     - [\*-win7-windows-msvc](platform-support/win7-windows-msvc.md)
     - [x86_64-fortanix-unknown-sgx](platform-support/x86_64-fortanix-unknown-sgx.md)
diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md
index 8c1769a8c77..a3b70e7f977 100644
--- a/src/doc/rustc/src/codegen-options/index.md
+++ b/src/doc/rustc/src/codegen-options/index.md
@@ -110,6 +110,19 @@ It takes a path to [the dlltool executable](https://sourceware.org/binutils/docs
 If this flag is not specified, a dlltool executable will be inferred based on
 the host environment and target.
 
+## dwarf-version
+
+This option controls the version of DWARF that the compiler emits, on platforms
+that use DWARF to encode debug information. It takes one of the following
+values:
+
+* `2`: DWARF version 2 (the default on certain platforms, like Android).
+* `3`: DWARF version 3 (the default on certain platforms, like AIX).
+* `4`: DWARF version 4 (the default on most platforms, like Linux & macOS).
+* `5`: DWARF version 5.
+
+DWARF version 1 is not supported.
+
 ## embed-bitcode
 
 This flag controls whether or not the compiler embeds LLVM bitcode into object
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index bc97568f85c..9870e5011eb 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -34,11 +34,10 @@ target | notes
 -------|-------
 [`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+)
 `aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1, glibc 2.17+)
-`i686-pc-windows-gnu` | 32-bit MinGW (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI]
 `i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI]
 `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+, Pentium 4) [^x86_32-floats-return-ABI]
 [`x86_64-apple-darwin`](platform-support/apple-darwin.md) | 64-bit macOS (10.12+, Sierra+)
-`x86_64-pc-windows-gnu` | 64-bit MinGW (Windows 10+, Windows Server 2016+)
+[`x86_64-pc-windows-gnu`](platform-support/windows-gnu.md) | 64-bit MinGW (Windows 10+, Windows Server 2016+)
 `x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 10+, Windows Server 2016+)
 `x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 3.2+, glibc 2.17+)
 
@@ -96,6 +95,7 @@ target | notes
 [`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | Armv7-A OpenHarmony
 [`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36)
 [`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, musl 1.2.5)
+[`i686-pc-windows-gnu`](platform-support/windows-gnu.md) | 32-bit MinGW (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI]
 `powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2, glibc 2.17)
 `powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2, glibc 2.17)
 [`powerpc64le-unknown-linux-gnu`](platform-support/powerpc64le-unknown-linux-gnu.md) | PPC64LE Linux (kernel 3.10, glibc 2.17)
@@ -143,7 +143,7 @@ target | std | notes
 [`aarch64-apple-ios-macabi`](platform-support/apple-ios-macabi.md) | ✓ | Mac Catalyst on ARM64
 [`aarch64-apple-ios-sim`](platform-support/apple-ios.md) | ✓ | Apple iOS Simulator on ARM64
 [`aarch64-linux-android`](platform-support/android.md) | ✓ | ARM64 Android
-[`aarch64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ARM64 MinGW (Windows 10+), LLVM ABI
+[`aarch64-pc-windows-gnullvm`](platform-support/windows-gnullvm.md) | ✓ | ARM64 MinGW (Windows 10+), LLVM ABI
 [`aarch64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | ARM64 Fuchsia
 `aarch64-unknown-none` | * | Bare ARM64, hardfloat
 `aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat
@@ -166,7 +166,7 @@ target | std | notes
 `i586-unknown-linux-gnu` | ✓ | 32-bit Linux (kernel 3.2, glibc 2.17, original Pentium) [^x86_32-floats-x87]
 `i586-unknown-linux-musl` | ✓ | 32-bit Linux (musl 1.2.3, original Pentium) [^x86_32-floats-x87]
 [`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android ([Pentium 4 plus various extensions](https://developer.android.com/ndk/guides/abis.html#x86)) [^x86_32-floats-return-ABI]
-[`i686-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | 32-bit x86 MinGW (Windows 10+, Pentium 4), LLVM ABI [^x86_32-floats-return-ABI]
+[`i686-pc-windows-gnullvm`](platform-support/windows-gnullvm.md) | ✓ | 32-bit x86 MinGW (Windows 10+, Pentium 4), LLVM ABI [^x86_32-floats-return-ABI]
 [`i686-unknown-freebsd`](platform-support/freebsd.md) | ✓ | 32-bit x86 FreeBSD (Pentium 4) [^x86_32-floats-return-ABI]
 `i686-unknown-linux-musl` | ✓ | 32-bit Linux with musl 1.2.3 (Pentium 4) [^x86_32-floats-return-ABI]
 [`i686-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 32-bit UEFI (Pentium 4, softfloat)
@@ -202,7 +202,7 @@ target | std | notes
 [`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX
 [`x86_64-linux-android`](platform-support/android.md) | ✓ | 64-bit x86 Android
 [`x86_64-pc-solaris`](platform-support/solaris.md) | ✓ | 64-bit x86 Solaris 11.4
-[`x86_64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | 64-bit x86 MinGW (Windows 10+), LLVM ABI
+[`x86_64-pc-windows-gnullvm`](platform-support/windows-gnullvm.md) | ✓ | 64-bit x86 MinGW (Windows 10+), LLVM ABI
 [`x86_64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | 64-bit x86 Fuchsia
 `x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27)
 [`x86_64-unknown-none`](platform-support/x86_64-unknown-none.md) | * | Freestanding/bare-metal x86_64, softfloat
@@ -407,6 +407,7 @@ target | std | host | notes
 [`wasm32-wali-linux-musl`](platform-support/wasm32-wali-linux.md) | ? |  | WebAssembly with [WALI](https://github.com/arjunr2/WALI)
 [`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ✓ |  | x86 64-bit tvOS
 [`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ |  | x86 64-bit Apple WatchOS simulator
+[`x86_64-lynx-lynxos178`](platform-support/lynxos178.md) |   |  | x86_64 LynxOS-178
 [`x86_64-pc-cygwin`](platform-support/x86_64-pc-cygwin.md) | ✓ |  | 64-bit x86 Cygwin |
 [`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ |  | x86 64-bit QNX Neutrino 7.1 RTOS with default network stack (io-pkt) |
 [`x86_64-pc-nto-qnx710_iosock`](platform-support/nto-qnx.md) | ✓ |  | x86 64-bit QNX Neutrino 7.1 RTOS with new network stack (io-sock) |
diff --git a/src/doc/rustc/src/platform-support/lynxos178.md b/src/doc/rustc/src/platform-support/lynxos178.md
new file mode 100644
index 00000000000..6463f95a0b8
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/lynxos178.md
@@ -0,0 +1,77 @@
+# `*-lynxos178-*`
+
+**Tier: 3**
+
+Targets for the LynxOS-178 operating system.
+
+[LynxOS-178](https://www.lynx.com/products/lynxos-178-do-178c-certified-posix-rtos)
+is a commercial RTOS designed for safety-critical real-time systems.  It is
+developed by Lynx Software Technologies as part of the
+[MOSA.ic](https://www.lynx.com/solutions/safe-and-secure-operating-environment)
+product suite.
+
+Target triples available:
+- `x86_64-lynx-lynxos178`
+
+## Target maintainers
+
+- Renat Fatykhov, https://github.com/rfatykhov-lynx
+
+## Requirements
+
+To build Rust programs for LynxOS-178, you must first have LYNX MOSA.ic
+installed on the build machine.
+
+This target supports only cross-compilation, from the same hosts supported by
+the Lynx CDK.
+
+Currently only `no_std` programs are supported. Work to support `std` is in
+progress.
+
+## Building the target
+
+You can build Rust with support for x86_64-lynx-lynxos178 by adding that
+to the `target` list in `config.toml`, and then running `./x build --target
+x86_64-lynx-lynxos178 compiler`.
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for this target. To compile for
+this target, you will need to build Rust with the target enabled (see "Building
+the target" above).
+
+Before executing `cargo`, you must configure the environment to build LynxOS-178
+binaries by running `source setup.sh` from the los178 directory.
+
+If your program/crates contain procedural macros, Rust must be able to build
+binaries for the host as well. The host gcc is hidden by sourcing setup.sh.  To
+deal with this, add the following to your project's `.cargo/config.toml`:
+```toml
+[target.x86_64-unknown-linux-gnu]
+linker = "lynx-host-gcc"
+```
+(If necessary substitute your host target triple for x86_64-unknown-linux-gnu.)
+
+To point `cargo` at the correct rustc binary, set the RUSTC environment
+variable.
+
+The core library should be usable. You can try by building it as part of your
+project:
+```bash
+cargo +nightly build -Z build-std=core --target x86_64-lynx-lynxos178
+```
+
+## Testing
+
+Binaries built with rust can be provided to a LynxOS-178 instance on its file
+system, where they can be executed. Rust binaries tend to be large, so it may
+be necessary to strip them first.
+
+It is possible to run the Rust testsuite by providing a test runner that takes
+the test binary and executes it under LynxOS-178. Most (all?) tests won't run
+without std support though, which is not yet supported.
+
+## Cross-compilation toolchains and C code
+
+LYNX MOSA.ic comes with all the tools required to cross-compile C code for
+LynxOS-178.
diff --git a/src/doc/rustc/src/platform-support/windows-gnu.md b/src/doc/rustc/src/platform-support/windows-gnu.md
new file mode 100644
index 00000000000..a867ebcfe25
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/windows-gnu.md
@@ -0,0 +1,32 @@
+# \*-windows-gnu
+
+**⚠️ This documentation page is a stub, you can help improving it by sending a PR. ⚠️**
+
+**Tier: 1/2 (with host tools)**
+
+Target triples available:
+- `i686-pc-windows-gnu`: Tier 2
+- `x86_64-pc-windows-gnu`: Tier 1
+
+## Target maintainers
+
+**⚠️ These targets do not have any maintainers and are not properly maintained. ⚠️**
+
+If you are using this target, consider signing up to become a target maintainer.
+See the target tier policy for details.
+Without maintainers, these targets may be demoted in the future.
+
+## Requirements
+
+These targets support std and host tools.
+
+Unlike their MSVC counterparts, windows-gnu targets support cross-compilation and are free of all MSVC licensing implications.
+
+They follow Windows calling convention for `extern "C"`.
+
+Like with any other Windows target, created binaries are in PE format.
+
+## Building Rust programs
+
+Rust does ship a pre-compiled std library for those targets.
+That means one can easily compile and cross-compile for those targets from other hosts if C proper toolchain is installed.
diff --git a/src/doc/rustc/src/platform-support/pc-windows-gnullvm.md b/src/doc/rustc/src/platform-support/windows-gnullvm.md
index f14fe7df422..1ff559fe960 100644
--- a/src/doc/rustc/src/platform-support/pc-windows-gnullvm.md
+++ b/src/doc/rustc/src/platform-support/windows-gnullvm.md
@@ -1,8 +1,8 @@
-# \*-pc-windows-gnullvm
+# \*-windows-gnullvm
 
 **Tier: 2 (without host tools)**
 
-Windows targets similar to `*-pc-windows-gnu` but using UCRT as the runtime and various LLVM tools/libraries instead of GCC/Binutils.
+Windows targets similar to `*-windows-gnu` but using UCRT as the runtime and various LLVM tools/libraries instead of GCC/Binutils.
 
 Target triples available so far:
 - `aarch64-pc-windows-gnullvm`
@@ -17,9 +17,9 @@ Target triples available so far:
 ## Requirements
 
 The easiest way to obtain these targets is cross-compilation, but native build from `x86_64-pc-windows-gnu` is possible with few hacks which I don't recommend.
-Std support is expected to be on par with `*-pc-windows-gnu`.
+Std support is expected to be on par with `*-windows-gnu`.
 
-Binaries for this target should be at least on par with `*-pc-windows-gnu` in terms of requirements and functionality.
+Binaries for this target should be at least on par with `*-windows-gnu` in terms of requirements and functionality.
 
 Those targets follow Windows calling convention for `extern "C"`.
 
diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md
index 12037b5992e..031e59d86e1 100644
--- a/src/doc/style-guide/src/expressions.md
+++ b/src/doc/style-guide/src/expressions.md
@@ -521,8 +521,11 @@ self.pre_comment.as_ref().map_or(
 
 ## Control flow expressions
 
-This section covers `if`, `if let`, `loop`, `while`, `while let`, and `for`
-expressions.
+This section covers `for` and `loop` expressions, as well as `if` and `while`
+expressions with their sub-expression variants. This includes those with a
+single `let` sub-expression (i.e. `if let` and `while let`)
+as well as "let-chains": those with one or more `let` sub-expressions and
+one or more bool-type conditions (i.e.  `if a && let Some(b) = c`).
 
 Put the keyword, any initial clauses, and the opening brace of the block all on
 a single line, if they fit. Apply the usual rules for [block
@@ -548,10 +551,11 @@ if let ... {
 }
 ```
 
-If the control line needs to be broken, prefer to break before the `=` in `*
-let` expressions and before `in` in a `for` expression; block-indent the
-following line. If the control line is broken for any reason, put the opening
-brace on its own line, not indented. Examples:
+If the control line needs to be broken, then prefer breaking after the `=` for any
+`let` sub-expression in an `if` or `while` expression that does not fit,
+and before `in` in a `for` expression; the following line should be block indented.
+If the control line is broken for any reason, then the opening brace should be on its
+own line and not indented. Examples:
 
 ```rust
 while let Some(foo)
@@ -572,6 +576,68 @@ if a_long_expression
 {
     ...
 }
+
+if let Some(a) = b
+    && another_long_expression
+    && a_third_long_expression
+{
+    // ...
+}
+
+if let Some(relatively_long_thing)
+    = a_long_expression
+    && another_long_expression
+    && a_third_long_expression
+{
+    // ...
+}
+
+if some_expr
+    && another_long_expression
+    && let Some(relatively_long_thing) =
+        a_long_long_long_long_long_long_really_reallllllllllyyyyyyy_long_expression
+    && a_third_long_expression
+{
+    // ...
+}
+```
+
+A let-chain control line is allowed to be formatted on a single line provided
+it only consists of two clauses, with the first, left-hand side operand being a literal or an
+`ident` (which can optionally be preceded by any number of unary prefix operators),
+and the second, right-hand side operand being a single-line `let` clause. Otherwise,
+the control line must be broken and formatted according to the above rules. For example:
+
+```rust
+if a && let Some(b) = foo() {
+    // ...
+}
+
+if true && let Some(b) = foo() {
+    // ...
+}
+
+let operator = if !from_hir_call && let Some(p) = parent {
+    // ...
+};
+
+if let Some(b) = foo()
+    && a
+{
+    // ..
+}
+
+if foo()
+    && let Some(b) = bar
+{
+    // ...
+}
+
+if gen_pos != GenericArgPosition::Type
+    && let Some(b) = gen_args.bindings.first()
+{
+    // ..
+}
 ```
 
 Where the initial clause spans multiple lines and ends with one or more closing
diff --git a/src/doc/unstable-book/src/compiler-flags/dwarf-version.md b/src/doc/unstable-book/src/compiler-flags/dwarf-version.md
deleted file mode 100644
index e88799d2cf0..00000000000
--- a/src/doc/unstable-book/src/compiler-flags/dwarf-version.md
+++ /dev/null
@@ -1,13 +0,0 @@
-## `dwarf-version`
-
-The tracking issue for this feature is: <https://github.com/rust-lang/rust/issues/103057>
-
-----------------------------
-
-This option controls the version of DWARF that the compiler emits, on platforms
-that use DWARF to encode debug information. It takes one of the following
-values:
-
-* `2`: DWARF version 2 (the default on certain platforms, like macOS).
-* `4`: DWARF version 4 (the default on certain platforms, like Linux).
-* `5`: DWARF version 5.
diff --git a/src/doc/unstable-book/src/language-features/import-trait-associated-functions.md b/src/doc/unstable-book/src/language-features/import-trait-associated-functions.md
new file mode 100644
index 00000000000..0ae5915361e
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/import-trait-associated-functions.md
@@ -0,0 +1,22 @@
+# import_trait_associated_functions
+
+The tracking issue for this feature is: [#134691]
+
+[#134691]: https://github.com/rust-lang/rust/issues/134691
+
+------------------------
+
+This feature allows importing associated functions and constants from traits and then using them like regular items.
+
+```rust
+#![feature(import_trait_associated_functions)]
+
+use std::ops::Add::add;
+
+fn main() {
+    let numbers = vec![1, 2, 3, 4, 5, 6];
+    let sum = numbers.into_iter().reduce(add); // instead of `.reduce(Add:add)`
+
+    assert_eq!(sum, Some(21));
+}
+```
diff --git a/src/doc/unstable-book/src/language-features/intrinsics.md b/src/doc/unstable-book/src/language-features/intrinsics.md
index 975b400447e..9e59dd88998 100644
--- a/src/doc/unstable-book/src/language-features/intrinsics.md
+++ b/src/doc/unstable-book/src/language-features/intrinsics.md
@@ -52,9 +52,9 @@ with any regular function.
 Various intrinsics have native MIR operations that they correspond to. Instead of requiring
 backends to implement both the intrinsic and the MIR operation, the `lower_intrinsics` pass
 will convert the calls to the MIR operation. Backends do not need to know about these intrinsics
-at all. These intrinsics only make sense without a body, and can either be declared as a "rust-intrinsic"
-or as a `#[rustc_intrinsic]`. The body is never used, as calls to the intrinsic do not exist
-anymore after MIR analyses.
+at all. These intrinsics only make sense without a body, and can be declared as a `#[rustc_intrinsic]`.
+The body is never used as the lowering pass implements support for all backends, so we never have to
+use the fallback logic.
 
 ## Intrinsics without fallback logic
 
@@ -70,28 +70,3 @@ These are written without a body:
 #[rustc_intrinsic]
 pub fn abort() -> !;
 ```
-
-### Legacy extern ABI based intrinsics
-
-*This style is deprecated, always prefer the above form.*
-
-These are imported as if they were FFI functions, with the special
-`rust-intrinsic` ABI. For example, if one was in a freestanding
-context, but wished to be able to `transmute` between types, and
-perform efficient pointer arithmetic, one would import those functions
-via a declaration like
-
-```rust
-#![feature(intrinsics)]
-#![allow(internal_features)]
-# fn main() {}
-
-extern "rust-intrinsic" {
-    fn transmute<T, U>(x: T) -> U;
-
-    fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
-}
-```
-
-As with any other FFI functions, these are by default always `unsafe` to call.
-You can add `#[rustc_safe_intrinsic]` to the intrinsic to make it safe to call.
diff --git a/src/doc/unstable-book/src/language-features/offset-of-enum.md b/src/doc/unstable-book/src/language-features/offset-of-enum.md
index 1960d6299eb..78c0d87f639 100644
--- a/src/doc/unstable-book/src/language-features/offset-of-enum.md
+++ b/src/doc/unstable-book/src/language-features/offset-of-enum.md
@@ -1,4 +1,4 @@
-# `offset_of_slice`
+# `offset_of_enum`
 
 The tracking issue for this feature is: [#120141]
 
diff --git a/src/doc/unstable-book/src/language-features/type-alias-impl-trait.md b/src/doc/unstable-book/src/language-features/type-alias-impl-trait.md
new file mode 100644
index 00000000000..a6fb25a55be
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/type-alias-impl-trait.md
@@ -0,0 +1,159 @@
+# `type_alias_impl_trait`
+
+The tracking issue for this feature is: [#63063]
+
+------------------------
+
+> This feature is not to be confused with [`trait_alias`] or [`impl_trait_in_assoc_type`].
+
+### What is `impl Trait`?
+
+`impl Trait` in return position is useful for declaring types that are constrained by traits, but whose concrete type should be hidden:
+
+```rust
+use std::fmt::Debug;
+
+fn new() -> impl Debug {
+    42
+}
+
+fn main() {
+    let thing = new();
+    // What actually is a `thing`?
+    // No idea but we know it implements `Debug`, so we can debug print it
+    println!("{thing:?}");
+}
+```
+
+See the [reference] for more information about `impl Trait` in return position.
+
+### `type_alias_impl_trait`
+
+However, we might want to use an `impl Trait` in multiple locations but actually use the same concrete type everywhere while keeping it hidden.
+This can be useful in libraries where you want to hide implementation details.
+
+The `#[define_opaque]` attribute must be used to explicitly list opaque items constrained by the item it's on.
+
+```rust
+#![feature(type_alias_impl_trait)]
+# #![allow(unused_variables, dead_code)]
+trait Trait {}
+
+struct MyType;
+
+impl Trait for MyType {}
+
+type Alias = impl Trait;
+
+#[define_opaque(Alias)] // To constrain the type alias to `MyType`
+fn new() -> Alias {
+    MyType
+}
+
+#[define_opaque(Alias)] // So we can name the concrete type inside this item
+fn main() {
+    let thing: MyType = new();
+}
+
+// It can be a part of a struct too
+struct HaveAlias {
+    stuff: String,
+    thing: Alias,
+}
+```
+
+In this example, the concrete type referred to by `Alias` is guaranteed to be the same wherever `Alias` occurs.
+
+> Orginally this feature included type aliases as an associated type of a trait. In [#110237] this was split off to [`impl_trait_in_assoc_type`].
+
+### `type_alias_impl_trait` in argument position.
+
+Note that using `Alias` as an argument type is *not* the same as argument-position `impl Trait`, as `Alias` refers to a unique type, whereas the concrete type for argument-position `impl Trait` is chosen by the caller.
+
+```rust
+# #![feature(type_alias_impl_trait)]
+# #![allow(unused_variables)]
+# pub mod x {
+# pub trait Trait {}
+#
+# struct MyType;
+#
+# impl Trait for MyType {}
+#
+# pub type Alias = impl Trait;
+#
+# #[define_opaque(Alias)]
+# pub fn new() -> Alias {
+#     MyType
+# }
+# }
+# use x::*;
+// this...
+pub fn take_alias(x: Alias) {
+    // ...
+}
+
+// ...is *not* the same as
+pub fn take_impl(x: impl Trait) {
+    // ...
+}
+# fn main(){}
+```
+
+```rust,compile_fail,E0308
+# #![feature(type_alias_impl_trait)]
+# #![allow(unused_variables)]
+# pub mod x {
+# pub trait Trait {}
+#
+# struct MyType;
+#
+# impl Trait for MyType {}
+#
+# pub type Alias = impl Trait;
+#
+# #[define_opaque(Alias)]
+# pub fn new() -> Alias {
+#     MyType
+# }
+# }
+# use x::*;
+# pub fn take_alias(x: Alias) {
+#     // ...
+# }
+#
+# pub fn take_impl(x: impl Trait) {
+#    // ...
+# }
+#
+// a user's crate using the trait and type alias
+struct UserType;
+impl Trait for UserType {}
+
+# fn main(){
+let x = UserType;
+take_alias(x);
+// ERROR expected opaque type, found `UserType`
+// this function *actually* takes a `MyType` as is constrained in `new`
+
+let x = UserType;
+take_impl(x);
+// OK
+
+let x = new();
+take_alias(x);
+// OK
+
+let x = new();
+take_impl(x);
+// OK
+# }
+```
+
+Note that the user cannot use `#[define_opaque(Alias)]` to reify the opaque type because only the crate where the type alias is declared may do so. But if this happened in the same crate and the opaque type was reified, they'd get a familiar error: "expected `MyType`, got `UserType`".
+
+[#63063]: https://github.com/rust-lang/rust/issues/63063
+[#110237]: https://github.com/rust-lang/rust/pull/110237
+[reference]: https://doc.rust-lang.org/stable/reference/types/impl-trait.html#abstract-return-types
+[`trait_alias`]: ./trait-alias.md
+[`impl_trait_in_assoc_type`]: ./impl-trait-in-assoc-type.md
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index 909b81a723b..27ae0553c60 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -9,7 +9,7 @@ path = "lib.rs"
 
 [dependencies]
 arrayvec = { version = "0.7", default-features = false }
-rinja = { version = "0.3", default-features = false, features = ["config"] }
+askama = { version = "0.13", default-features = false, features = ["alloc", "config", "derive"] }
 base64 = "0.21.7"
 itertools = "0.12"
 indexmap = "2"
diff --git a/src/librustdoc/rinja.toml b/src/librustdoc/askama.toml
index 2732c4bc61e..2732c4bc61e 100644
--- a/src/librustdoc/rinja.toml
+++ b/src/librustdoc/askama.toml
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index a48f5c623cd..138ac3c97f7 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -182,7 +182,7 @@ fn clean_param_env<'tcx>(
                     .is_some_and(|pred| tcx.lang_items().sized_trait() == Some(pred.def_id()))
         })
         .map(|pred| {
-            fold_regions(tcx, pred, |r, _| match *r {
+            fold_regions(tcx, pred, |r, _| match r.kind() {
                 // FIXME: Don't `unwrap_or`, I think we should panic if we encounter an infer var that
                 // we can't map to a concrete region. However, `AutoTraitFinder` *does* leak those kinds
                 // of `ReVar`s for some reason at the time of writing. See `rustdoc-ui/` tests.
@@ -362,7 +362,7 @@ fn clean_region_outlives_constraints<'tcx>(
 }
 
 fn early_bound_region_name(region: Region<'_>) -> Option<Symbol> {
-    match *region {
+    match region.kind() {
         ty::ReEarlyParam(r) => Some(r.name),
         _ => None,
     }
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index e0e09b53fc2..2f6870e3c36 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -490,17 +490,17 @@ pub(crate) fn build_impl(
                         return true;
                     }
                     if let Some(associated_trait) = associated_trait {
-                        let assoc_kind = match item.kind {
-                            hir::ImplItemKind::Const(..) => ty::AssocKind::Const,
-                            hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn,
-                            hir::ImplItemKind::Type(..) => ty::AssocKind::Type,
+                        let assoc_tag = match item.kind {
+                            hir::ImplItemKind::Const(..) => ty::AssocTag::Const,
+                            hir::ImplItemKind::Fn(..) => ty::AssocTag::Fn,
+                            hir::ImplItemKind::Type(..) => ty::AssocTag::Type,
                         };
                         let trait_item = tcx
                             .associated_items(associated_trait.def_id)
-                            .find_by_name_and_kind(
+                            .find_by_ident_and_kind(
                                 tcx,
                                 item.ident,
-                                assoc_kind,
+                                assoc_tag,
                                 associated_trait.def_id,
                             )
                             .unwrap(); // SAFETY: For all impl items there exists trait item that has the same name.
@@ -524,10 +524,10 @@ pub(crate) fn build_impl(
                     if let Some(associated_trait) = associated_trait {
                         let trait_item = tcx
                             .associated_items(associated_trait.def_id)
-                            .find_by_name_and_kind(
+                            .find_by_ident_and_kind(
                                 tcx,
                                 item.ident(tcx),
-                                item.kind,
+                                item.as_tag(),
                                 associated_trait.def_id,
                             )
                             .unwrap(); // corresponding associated item has to exist
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index c08ae168d69..2a95acc622e 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -320,7 +320,7 @@ pub(crate) fn clean_middle_const<'tcx>(
 }
 
 pub(crate) fn clean_middle_region(region: ty::Region<'_>) -> Option<Lifetime> {
-    match *region {
+    match region.kind() {
         ty::ReStatic => Some(Lifetime::statik()),
         _ if !region.has_name() => None,
         ty::ReBound(_, ty::BoundRegion { kind: ty::BoundRegionKind::Named(_, name), .. }) => {
@@ -521,7 +521,7 @@ fn projection_to_path_segment<'tcx>(
     let item = cx.tcx.associated_item(def_id);
     let generics = cx.tcx.generics_of(def_id);
     PathSegment {
-        name: item.name,
+        name: item.name(),
         args: GenericArgs::AngleBracketed {
             args: clean_middle_generic_args(
                 cx,
@@ -1088,7 +1088,7 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[hir::Attrib
 
 enum FunctionArgs<'tcx> {
     Body(hir::BodyId),
-    Names(&'tcx [Option<Ident>]),
+    Idents(&'tcx [Option<Ident>]),
 }
 
 fn clean_function<'tcx>(
@@ -1104,8 +1104,8 @@ fn clean_function<'tcx>(
             FunctionArgs::Body(body_id) => {
                 clean_args_from_types_and_body_id(cx, sig.decl.inputs, body_id)
             }
-            FunctionArgs::Names(names) => {
-                clean_args_from_types_and_names(cx, sig.decl.inputs, names)
+            FunctionArgs::Idents(idents) => {
+                clean_args_from_types_and_names(cx, sig.decl.inputs, idents)
             }
         };
         let decl = clean_fn_decl_with_args(cx, sig.decl, Some(&sig.header), args);
@@ -1117,7 +1117,7 @@ fn clean_function<'tcx>(
 fn clean_args_from_types_and_names<'tcx>(
     cx: &mut DocContext<'tcx>,
     types: &[hir::Ty<'tcx>],
-    names: &[Option<Ident>],
+    idents: &[Option<Ident>],
 ) -> Arguments {
     fn nonempty_name(ident: &Option<Ident>) -> Option<Symbol> {
         if let Some(ident) = ident
@@ -1131,7 +1131,7 @@ fn clean_args_from_types_and_names<'tcx>(
 
     // If at least one argument has a name, use `_` as the name of unnamed
     // arguments. Otherwise omit argument names.
-    let default_name = if names.iter().any(|ident| nonempty_name(ident).is_some()) {
+    let default_name = if idents.iter().any(|ident| nonempty_name(ident).is_some()) {
         kw::Underscore
     } else {
         kw::Empty
@@ -1143,7 +1143,7 @@ fn clean_args_from_types_and_names<'tcx>(
             .enumerate()
             .map(|(i, ty)| Argument {
                 type_: clean_ty(ty, cx),
-                name: names.get(i).and_then(nonempty_name).unwrap_or(default_name),
+                name: idents.get(i).and_then(nonempty_name).unwrap_or(default_name),
                 is_const: false,
             })
             .collect(),
@@ -1193,7 +1193,7 @@ fn clean_poly_fn_sig<'tcx>(
     did: Option<DefId>,
     sig: ty::PolyFnSig<'tcx>,
 ) -> FnDecl {
-    let mut names = did.map_or(&[] as &[_], |did| cx.tcx.fn_arg_names(did)).iter();
+    let mut names = did.map_or(&[] as &[_], |did| cx.tcx.fn_arg_idents(did)).iter();
 
     // We assume all empty tuples are default return type. This theoretically can discard `-> ()`,
     // but shouldn't change any code meaning.
@@ -1270,8 +1270,8 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
                 let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Body(body));
                 MethodItem(m, None)
             }
-            hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => {
-                let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Names(names));
+            hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(idents)) => {
+                let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Idents(idents));
                 RequiredMethodItem(m)
             }
             hir::TraitItemKind::Type(bounds, Some(default)) => {
@@ -1340,7 +1340,7 @@ pub(crate) fn clean_impl_item<'tcx>(
 pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocContext<'_>) -> Item {
     let tcx = cx.tcx;
     let kind = match assoc_item.kind {
-        ty::AssocKind::Const => {
+        ty::AssocKind::Const { .. } => {
             let ty = clean_middle_ty(
                 ty::Binder::dummy(tcx.type_of(assoc_item.def_id).instantiate_identity()),
                 cx,
@@ -1374,10 +1374,10 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
                 }
             }
         }
-        ty::AssocKind::Fn => {
+        ty::AssocKind::Fn { has_self, .. } => {
             let mut item = inline::build_function(cx, assoc_item.def_id);
 
-            if assoc_item.fn_has_self_parameter {
+            if has_self {
                 let self_ty = match assoc_item.container {
                     ty::AssocItemContainer::Impl => {
                         tcx.type_of(assoc_item.container_id(tcx)).instantiate_identity()
@@ -1412,8 +1412,8 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
                 RequiredMethodItem(item)
             }
         }
-        ty::AssocKind::Type => {
-            let my_name = assoc_item.name;
+        ty::AssocKind::Type { .. } => {
+            let my_name = assoc_item.name();
 
             fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
                 match (&param.kind, arg) {
@@ -1554,7 +1554,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
         }
     };
 
-    Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name), kind, cx)
+    Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name()), kind, cx)
 }
 
 fn first_non_private_clean_path<'tcx>(
@@ -1941,7 +1941,7 @@ fn clean_trait_object_lifetime_bound<'tcx>(
     // Since there is a semantic difference between an implicitly elided (i.e. "defaulted") object
     // lifetime and an explicitly elided object lifetime (`'_`), we intentionally don't hide the
     // latter contrary to `clean_middle_region`.
-    match *region {
+    match region.kind() {
         ty::ReStatic => Some(Lifetime::statik()),
         ty::ReEarlyParam(region) => Some(Lifetime(region.name)),
         ty::ReBound(_, ty::BoundRegion { kind: ty::BoundRegionKind::Named(_, name), .. }) => {
@@ -1972,7 +1972,7 @@ fn can_elide_trait_object_lifetime_bound<'tcx>(
     // > If there is a unique bound from the containing type then that is the default
     // If there is a default object lifetime and the given region is lexically equal to it, elide it.
     match default {
-        ObjectLifetimeDefault::Static => return *region == ty::ReStatic,
+        ObjectLifetimeDefault::Static => return region.kind() == ty::ReStatic,
         // FIXME(fmease): Don't compare lexically but respect de Bruijn indices etc. to handle shadowing correctly.
         ObjectLifetimeDefault::Arg(default) => return region.get_name() == default.get_name(),
         // > If there is more than one bound from the containing type then an explicit bound must be specified
@@ -1992,7 +1992,7 @@ fn can_elide_trait_object_lifetime_bound<'tcx>(
         // Note however that at the time of this writing it should be fine to disregard this subtlety
         // as we neither render const exprs faithfully anyway (hiding them in some places or using `_` instead)
         // nor show the contents of fn bodies.
-        [] => *region == ty::ReStatic,
+        [] => region.kind() == ty::ReStatic,
         // > If the trait is defined with a single lifetime bound then that bound is used.
         // > If 'static is used for any lifetime bound then 'static is used.
         // FIXME(fmease): Don't compare lexically but respect de Bruijn indices etc. to handle shadowing correctly.
@@ -2223,7 +2223,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
 
             Type::QPath(Box::new(QPathData {
                 assoc: PathSegment {
-                    name: cx.tcx.associated_item(def_id).name,
+                    name: cx.tcx.associated_item(def_id).name(),
                     args: GenericArgs::AngleBracketed {
                         args: clean_middle_generic_args(
                             cx,
@@ -2612,7 +2612,7 @@ fn clean_bare_fn_ty<'tcx>(
             .filter(|p| !is_elided_lifetime(p))
             .map(|x| clean_generic_param(cx, None, x))
             .collect();
-        let args = clean_args_from_types_and_names(cx, bare_fn.decl.inputs, bare_fn.param_names);
+        let args = clean_args_from_types_and_names(cx, bare_fn.decl.inputs, bare_fn.param_idents);
         let decl = clean_fn_decl_with_args(cx, bare_fn.decl, None, args);
         (generic_params, decl)
     });
@@ -3148,8 +3148,8 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
     let def_id = item.owner_id.to_def_id();
     cx.with_param_env(def_id, |cx| {
         let kind = match item.kind {
-            hir::ForeignItemKind::Fn(sig, names, generics) => ForeignFunctionItem(
-                clean_function(cx, &sig, generics, FunctionArgs::Names(names)),
+            hir::ForeignItemKind::Fn(sig, idents, generics) => ForeignFunctionItem(
+                clean_function(cx, &sig, generics, FunctionArgs::Idents(idents)),
                 sig.header.safety(),
             ),
             hir::ForeignItemKind::Static(ty, mutability, safety) => ForeignStaticItem(
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index d3ddb77c0b3..31aa84535cc 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -11,7 +11,6 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{BodyId, Mutability};
-use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety;
 use rustc_index::IndexVec;
 use rustc_metadata::rendered_const;
 use rustc_middle::span_bug;
@@ -518,7 +517,7 @@ impl Item {
                     Some(RenderedLink {
                         original_text: s.clone(),
                         new_text: link_text.clone(),
-                        tooltip: link_tooltip(*id, fragment, cx),
+                        tooltip: link_tooltip(*id, fragment, cx).to_string(),
                         href,
                     })
                 } else {
@@ -687,8 +686,6 @@ impl Item {
                 hir::FnHeader {
                     safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
                         hir::HeaderSafety::SafeTargetFeatures
-                    } else if abi == ExternAbi::RustIntrinsic {
-                        intrinsic_operation_unsafety(tcx, def_id.expect_local()).into()
                     } else {
                         safety.into()
                     },
@@ -2507,7 +2504,7 @@ impl Impl {
         self.trait_
             .as_ref()
             .map(|t| t.def_id())
-            .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name).collect())
+            .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name()).collect())
             .unwrap_or_default()
     }
 
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index f81db58950c..afcca81a485 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -304,6 +304,7 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
 
     Symbol::intern(&match &p.kind {
         // FIXME(never_patterns): does this make sense?
+        PatKind::Missing => unreachable!(),
         PatKind::Wild
         | PatKind::Err(_)
         | PatKind::Never
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index c47e42670c9..c4dea79370d 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -321,6 +321,7 @@ pub(crate) fn create_config(
                 (rustc_interface::DEFAULT_QUERY_PROVIDERS.typeck)(tcx, def_id)
             };
         }),
+        extra_symbols: Vec::new(),
         make_codegen_backend: None,
         registry: rustc_driver::diagnostics_registry(),
         ice_file: None,
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index a2808bddb3a..88eaa52c6de 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -191,6 +191,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions
         hash_untracked_state: None,
         register_lints: Some(Box::new(crate::lint::register_lints)),
         override_queries: None,
+        extra_symbols: Vec::new(),
         make_codegen_backend: None,
         registry: rustc_driver::diagnostics_registry(),
         ice_file: None,
diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs
index f891505d2a6..784d628805d 100644
--- a/src/librustdoc/doctest/runner.rs
+++ b/src/librustdoc/doctest/runner.rs
@@ -113,6 +113,7 @@ impl DocTestRunner {
 mod __doctest_mod {{
     use std::sync::OnceLock;
     use std::path::PathBuf;
+    use std::process::ExitCode;
 
     pub static BINARY_PATH: OnceLock<PathBuf> = OnceLock::new();
     pub const RUN_OPTION: &str = \"RUSTDOC_DOCTEST_RUN_NB_TEST\";
@@ -123,16 +124,17 @@ mod __doctest_mod {{
     }}
 
     #[allow(unused)]
-    pub fn doctest_runner(bin: &std::path::Path, test_nb: usize) -> Result<(), String> {{
+    pub fn doctest_runner(bin: &std::path::Path, test_nb: usize) -> ExitCode {{
         let out = std::process::Command::new(bin)
             .env(self::RUN_OPTION, test_nb.to_string())
             .args(std::env::args().skip(1).collect::<Vec<_>>())
             .output()
             .expect(\"failed to run command\");
         if !out.status.success() {{
-            Err(String::from_utf8_lossy(&out.stderr).to_string())
+            eprint!(\"{{}}\", String::from_utf8_lossy(&out.stderr));
+            ExitCode::FAILURE
         }} else {{
-            Ok(())
+            ExitCode::SUCCESS
         }}
     }}
 }}
@@ -144,7 +146,6 @@ let tests = {{
     {ids}
     tests
 }};
-let test_marker = std::ffi::OsStr::new(__doctest_mod::RUN_OPTION);
 let test_args = &[{test_args}];
 const ENV_BIN: &'static str = \"RUSTDOC_DOCTEST_BIN_PATH\";
 
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 41e9a5a6651..4998c671b61 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -11,6 +11,7 @@ use std::borrow::Cow;
 use std::cmp::Ordering;
 use std::fmt::{self, Display, Write};
 use std::iter::{self, once};
+use std::slice;
 
 use itertools::Either;
 use rustc_abi::ExternAbi;
@@ -650,33 +651,35 @@ pub(crate) fn href_relative_parts<'fqp>(
     }
 }
 
-pub(crate) fn link_tooltip(did: DefId, fragment: &Option<UrlFragment>, cx: &Context<'_>) -> String {
-    let cache = cx.cache();
-    let Some((fqp, shortty)) = cache.paths.get(&did).or_else(|| cache.external_paths.get(&did))
-    else {
-        return String::new();
-    };
-    let mut buf = String::new();
-    let fqp = if *shortty == ItemType::Primitive {
-        // primitives are documented in a crate, but not actually part of it
-        &fqp[fqp.len() - 1..]
-    } else {
-        fqp
-    };
-    if let &Some(UrlFragment::Item(id)) = fragment {
-        write_str(&mut buf, format_args!("{} ", cx.tcx().def_descr(id)));
-        for component in fqp {
-            write_str(&mut buf, format_args!("{component}::"));
-        }
-        write_str(&mut buf, format_args!("{}", cx.tcx().item_name(id)));
-    } else if !fqp.is_empty() {
-        let mut fqp_it = fqp.iter();
-        write_str(&mut buf, format_args!("{shortty} {}", fqp_it.next().unwrap()));
-        for component in fqp_it {
-            write_str(&mut buf, format_args!("::{component}"));
+pub(crate) fn link_tooltip(
+    did: DefId,
+    fragment: &Option<UrlFragment>,
+    cx: &Context<'_>,
+) -> impl fmt::Display {
+    fmt::from_fn(move |f| {
+        let cache = cx.cache();
+        let Some((fqp, shortty)) = cache.paths.get(&did).or_else(|| cache.external_paths.get(&did))
+        else {
+            return Ok(());
+        };
+        let fqp = if *shortty == ItemType::Primitive {
+            // primitives are documented in a crate, but not actually part of it
+            slice::from_ref(fqp.last().unwrap())
+        } else {
+            fqp
+        };
+        if let &Some(UrlFragment::Item(id)) = fragment {
+            write!(f, "{} ", cx.tcx().def_descr(id))?;
+            for component in fqp {
+                write!(f, "{component}::")?;
+            }
+            write!(f, "{}", cx.tcx().item_name(id))?;
+        } else if !fqp.is_empty() {
+            write!(f, "{shortty} ")?;
+            fqp.iter().joined("::", f)?;
         }
-    }
-    buf
+        Ok(())
+    })
 }
 
 /// Used to render a [`clean::Path`].
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index df70df062fe..44b3be23914 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -1,7 +1,7 @@
 use std::fmt::{self, Display};
 use std::path::PathBuf;
 
-use rinja::Template;
+use askama::Template;
 use rustc_data_structures::fx::FxIndexMap;
 
 use super::static_files::{STATIC_FILES, StaticFiles};
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 334a7a86989..44134bda5ea 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -721,7 +721,7 @@ pub(crate) fn find_codes<T: doctest::DocTestVisitor>(
     extra_info: Option<&ExtraInfo<'_>>,
     include_non_rust: bool,
 ) {
-    let mut parser = Parser::new(doc).into_offset_iter();
+    let mut parser = Parser::new_ext(doc, main_body_opts()).into_offset_iter();
     let mut prev_offset = 0;
     let mut nb_lines = 0;
     let mut register_header = None;
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 5f69e79f3ab..596ac665fc3 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -5,7 +5,7 @@ use std::io;
 use std::path::{Path, PathBuf};
 use std::sync::mpsc::{Receiver, channel};
 
-use rinja::Template;
+use askama::Template;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE};
 use rustc_middle::ty::TyCtxt;
@@ -650,15 +650,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
 
         bar.render_into(&mut sidebar).unwrap();
 
-        let v = layout::render(
-            &shared.layout,
-            &page,
-            sidebar,
-            BufDisplay(|buf: &mut String| {
-                all.print(buf);
-            }),
-            &shared.style_files,
-        );
+        let v = layout::render(&shared.layout, &page, sidebar, all.print(), &shared.style_files);
         shared.fs.write(final_file, v)?;
 
         // if to avoid writing help, settings files to doc root unless we're on the final invocation
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 2237e0f987b..94171ad6de8 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -13,6 +13,9 @@
 //! is cloned per-thread and contains information about what is currently being
 //! rendered.
 //!
+//! The main entry point to the rendering system is the implementation of
+//! `FormatRenderer` on `Context`.
+//!
 //! In order to speed up rendering (mostly because of markdown rendering), the
 //! rendering process has been parallelized. This parallelization is only
 //! exposed through the `crate` method on the context, and then also from the
@@ -37,13 +40,15 @@ mod span_map;
 mod type_layout;
 mod write_shared;
 
+use std::borrow::Cow;
 use std::collections::VecDeque;
 use std::fmt::{self, Display as _, Write};
 use std::iter::Peekable;
 use std::path::PathBuf;
 use std::{fs, str};
 
-use rinja::Template;
+use askama::Template;
+use itertools::Either;
 use rustc_attr_parsing::{
     ConstStability, DeprecatedSince, Deprecation, RustcVersion, StabilityLevel, StableSince,
 };
@@ -90,15 +95,28 @@ pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display {
 /// Specifies whether rendering directly implemented trait items or ones from a certain Deref
 /// impl.
 #[derive(Copy, Clone, Debug)]
-pub(crate) enum AssocItemRender<'a> {
+enum AssocItemRender<'a> {
     All,
     DerefFor { trait_: &'a clean::Path, type_: &'a clean::Type, deref_mut_: bool },
 }
 
+impl AssocItemRender<'_> {
+    fn render_mode(&self) -> RenderMode {
+        match self {
+            Self::All => RenderMode::Normal,
+            &Self::DerefFor { deref_mut_, .. } => RenderMode::ForDeref { mut_: deref_mut_ },
+        }
+    }
+
+    fn class(&self) -> Option<&'static str> {
+        if let Self::DerefFor { .. } = self { Some("impl-items") } else { None }
+    }
+}
+
 /// For different handling of associated items from the Deref target of a type rather than the type
 /// itself.
 #[derive(Copy, Clone, PartialEq)]
-pub(crate) enum RenderMode {
+enum RenderMode {
     Normal,
     ForDeref { mut_: bool },
 }
@@ -126,7 +144,7 @@ pub(crate) struct IndexItem {
 
 /// A type used for the search index.
 #[derive(Debug, Eq, PartialEq)]
-pub(crate) struct RenderType {
+struct RenderType {
     id: Option<RenderTypeId>,
     generics: Option<Vec<RenderType>>,
     bindings: Option<Vec<(RenderTypeId, Vec<RenderType>)>>,
@@ -137,7 +155,7 @@ impl RenderType {
     // The contents of the lists are always integers in self-terminating hex
     // form, handled by `RenderTypeId::write_to_string`, so no commas are
     // needed to separate the items.
-    pub fn write_to_string(&self, string: &mut String) {
+    fn write_to_string(&self, string: &mut String) {
         fn write_optional_id(id: Option<RenderTypeId>, string: &mut String) {
             // 0 is a sentinel, everything else is one-indexed
             match id {
@@ -177,7 +195,7 @@ impl RenderType {
 }
 
 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub(crate) enum RenderTypeId {
+enum RenderTypeId {
     DefId(DefId),
     Primitive(clean::PrimitiveType),
     AssociatedType(Symbol),
@@ -186,7 +204,7 @@ pub(crate) enum RenderTypeId {
 }
 
 impl RenderTypeId {
-    pub fn write_to_string(&self, string: &mut String) {
+    fn write_to_string(&self, string: &mut String) {
         let id: i32 = match &self {
             // 0 is a sentinel, everything else is one-indexed
             // concrete type
@@ -209,7 +227,7 @@ pub(crate) struct IndexItemFunctionType {
 }
 
 impl IndexItemFunctionType {
-    pub fn write_to_string<'a>(
+    fn write_to_string<'a>(
         &'a self,
         string: &mut String,
         backref_queue: &mut VecDeque<&'a IndexItemFunctionType>,
@@ -309,7 +327,7 @@ impl ItemEntry {
 }
 
 impl ItemEntry {
-    pub(crate) fn print(&self) -> impl fmt::Display {
+    fn print(&self) -> impl fmt::Display {
         fmt::from_fn(move |f| write!(f, "<a href=\"{}\">{}</a>", self.url, Escape(&self.name)))
     }
 }
@@ -436,44 +454,49 @@ impl AllTypes {
         sections
     }
 
-    fn print(&self, f: &mut String) {
-        fn print_entries(f: &mut String, e: &FxIndexSet<ItemEntry>, kind: ItemSection) {
-            if !e.is_empty() {
+    fn print(&self) -> impl fmt::Display {
+        fn print_entries(e: &FxIndexSet<ItemEntry>, kind: ItemSection) -> impl fmt::Display {
+            fmt::from_fn(move |f| {
+                if e.is_empty() {
+                    return Ok(());
+                }
+
                 let mut e: Vec<&ItemEntry> = e.iter().collect();
                 e.sort();
-                write_str(
+                write!(
                     f,
-                    format_args!(
-                        "<h3 id=\"{id}\">{title}</h3><ul class=\"all-items\">",
-                        id = kind.id(),
-                        title = kind.name(),
-                    ),
-                );
+                    "<h3 id=\"{id}\">{title}</h3><ul class=\"all-items\">",
+                    id = kind.id(),
+                    title = kind.name(),
+                )?;
 
                 for s in e.iter() {
-                    write_str(f, format_args!("<li>{}</li>", s.print()));
+                    write!(f, "<li>{}</li>", s.print())?;
                 }
 
-                f.push_str("</ul>");
-            }
+                f.write_str("</ul>")
+            })
         }
 
-        f.push_str("<h1>List of all items</h1>");
-        // Note: print_entries does not escape the title, because we know the current set of titles
-        // doesn't require escaping.
-        print_entries(f, &self.structs, ItemSection::Structs);
-        print_entries(f, &self.enums, ItemSection::Enums);
-        print_entries(f, &self.unions, ItemSection::Unions);
-        print_entries(f, &self.primitives, ItemSection::PrimitiveTypes);
-        print_entries(f, &self.traits, ItemSection::Traits);
-        print_entries(f, &self.macros, ItemSection::Macros);
-        print_entries(f, &self.attribute_macros, ItemSection::AttributeMacros);
-        print_entries(f, &self.derive_macros, ItemSection::DeriveMacros);
-        print_entries(f, &self.functions, ItemSection::Functions);
-        print_entries(f, &self.type_aliases, ItemSection::TypeAliases);
-        print_entries(f, &self.trait_aliases, ItemSection::TraitAliases);
-        print_entries(f, &self.statics, ItemSection::Statics);
-        print_entries(f, &self.constants, ItemSection::Constants);
+        fmt::from_fn(|f| {
+            f.write_str("<h1>List of all items</h1>")?;
+            // Note: print_entries does not escape the title, because we know the current set of titles
+            // doesn't require escaping.
+            print_entries(&self.structs, ItemSection::Structs).fmt(f)?;
+            print_entries(&self.enums, ItemSection::Enums).fmt(f)?;
+            print_entries(&self.unions, ItemSection::Unions).fmt(f)?;
+            print_entries(&self.primitives, ItemSection::PrimitiveTypes).fmt(f)?;
+            print_entries(&self.traits, ItemSection::Traits).fmt(f)?;
+            print_entries(&self.macros, ItemSection::Macros).fmt(f)?;
+            print_entries(&self.attribute_macros, ItemSection::AttributeMacros).fmt(f)?;
+            print_entries(&self.derive_macros, ItemSection::DeriveMacros).fmt(f)?;
+            print_entries(&self.functions, ItemSection::Functions).fmt(f)?;
+            print_entries(&self.type_aliases, ItemSection::TypeAliases).fmt(f)?;
+            print_entries(&self.trait_aliases, ItemSection::TraitAliases).fmt(f)?;
+            print_entries(&self.statics, ItemSection::Statics).fmt(f)?;
+            print_entries(&self.constants, ItemSection::Constants).fmt(f)?;
+            Ok(())
+        })
     }
 }
 
@@ -760,7 +783,7 @@ fn short_item_info(
 
 // Render the list of items inside one of the sections "Trait Implementations",
 // "Auto Trait Implementations," "Blanket Trait Implementations" (on struct/enum pages).
-pub(crate) fn render_impls(
+fn render_impls(
     cx: &Context<'_>,
     mut w: impl Write,
     impls: &[&Impl],
@@ -1201,8 +1224,8 @@ impl<'a> AssocItemLink<'a> {
     }
 }
 
-pub fn write_section_heading(
-    title: &str,
+fn write_section_heading(
+    title: impl fmt::Display,
     id: &str,
     extra_class: Option<&str>,
     extra: impl fmt::Display,
@@ -1222,11 +1245,11 @@ pub fn write_section_heading(
     })
 }
 
-fn write_impl_section_heading(title: &str, id: &str) -> impl fmt::Display {
+fn write_impl_section_heading(title: impl fmt::Display, id: &str) -> impl fmt::Display {
     write_section_heading(title, id, None, "")
 }
 
-pub(crate) fn render_all_impls(
+fn render_all_impls(
     mut w: impl Write,
     cx: &Context<'_>,
     containing_item: &clean::Item,
@@ -1299,20 +1322,17 @@ fn render_assoc_items_inner(
     let (mut non_trait, traits): (Vec<_>, _) =
         v.iter().partition(|i| i.inner_impl().trait_.is_none());
     if !non_trait.is_empty() {
-        let mut close_tags = <Vec<&str>>::with_capacity(1);
-        let mut tmp_buf = String::new();
-        let (render_mode, id, class_html) = match what {
-            AssocItemRender::All => {
-                write_str(
-                    &mut tmp_buf,
-                    format_args!(
-                        "{}",
-                        write_impl_section_heading("Implementations", "implementations")
-                    ),
-                );
-                (RenderMode::Normal, "implementations-list".to_owned(), "")
-            }
-            AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
+        let render_mode = what.render_mode();
+        let class_html = what
+            .class()
+            .map(|class| fmt::from_fn(move |f| write!(f, r#" class="{class}""#)))
+            .maybe_display();
+        let (section_heading, id) = match what {
+            AssocItemRender::All => (
+                Either::Left(write_impl_section_heading("Implementations", "implementations")),
+                Cow::Borrowed("implementations-list"),
+            ),
+            AssocItemRender::DerefFor { trait_, type_, .. } => {
                 let id =
                     cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx))));
                 // the `impls.get` above only looks at the outermost type,
@@ -1326,25 +1346,27 @@ fn render_assoc_items_inner(
                     type_.is_doc_subtype_of(&impl_.inner_impl().for_, &cx.shared.cache)
                 });
                 let derived_id = cx.derive_id(&id);
-                close_tags.push("</details>");
-                write_str(
-                    &mut tmp_buf,
-                    format_args!(
-                        "<details class=\"toggle big-toggle\" open><summary>{}</summary>",
-                        write_impl_section_heading(
-                            &format!(
-                                "<span>Methods from {trait_}&lt;Target = {type_}&gt;</span>",
-                                trait_ = trait_.print(cx),
-                                type_ = type_.print(cx),
-                            ),
-                            &id,
-                        )
-                    ),
-                );
                 if let Some(def_id) = type_.def_id(cx.cache()) {
-                    cx.deref_id_map.borrow_mut().insert(def_id, id);
+                    cx.deref_id_map.borrow_mut().insert(def_id, id.clone());
                 }
-                (RenderMode::ForDeref { mut_: deref_mut_ }, derived_id, r#" class="impl-items""#)
+                (
+                    Either::Right(fmt::from_fn(move |f| {
+                        write!(
+                            f,
+                            "<details class=\"toggle big-toggle\" open><summary>{}</summary>",
+                            write_impl_section_heading(
+                                fmt::from_fn(|f| write!(
+                                    f,
+                                    "<span>Methods from {trait_}&lt;Target = {type_}&gt;</span>",
+                                    trait_ = trait_.print(cx),
+                                    type_ = type_.print(cx),
+                                )),
+                                &id,
+                            )
+                        )
+                    })),
+                    Cow::Owned(derived_id),
+                )
             }
         };
         let mut impls_buf = String::new();
@@ -1372,10 +1394,14 @@ fn render_assoc_items_inner(
             );
         }
         if !impls_buf.is_empty() {
-            write!(w, "{tmp_buf}<div id=\"{id}\"{class_html}>{impls_buf}</div>").unwrap();
-            for tag in close_tags.into_iter().rev() {
-                w.write_str(tag).unwrap();
-            }
+            write!(
+                w,
+                "{section_heading}<div id=\"{id}\"{class_html}>{impls_buf}</div>{}",
+                matches!(what, AssocItemRender::DerefFor { .. })
+                    .then_some("</details>")
+                    .maybe_display(),
+            )
+            .unwrap();
         }
     }
 
@@ -1473,10 +1499,7 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) ->
     }
 }
 
-pub(crate) fn notable_traits_button(
-    ty: &clean::Type,
-    cx: &Context<'_>,
-) -> Option<impl fmt::Display> {
+fn notable_traits_button(ty: &clean::Type, cx: &Context<'_>) -> Option<impl fmt::Display> {
     if ty.is_unit() {
         // Very common fast path.
         return None;
@@ -1588,10 +1611,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
     (format!("{:#}", ty.print(cx)), out)
 }
 
-pub(crate) fn notable_traits_json<'a>(
-    tys: impl Iterator<Item = &'a clean::Type>,
-    cx: &Context<'_>,
-) -> String {
+fn notable_traits_json<'a>(tys: impl Iterator<Item = &'a clean::Type>, cx: &Context<'_>) -> String {
     let mut mp: Vec<(String, String)> = tys.map(|ty| notable_traits_decl(ty, cx)).collect();
     mp.sort_by(|(name1, _html1), (name2, _html2)| name1.cmp(name2));
     struct NotableTraitsMap(Vec<(String, String)>);
@@ -1642,8 +1662,8 @@ fn render_impl(
         // `containing_item` is used for rendering stability info. If the parent is a trait impl,
         // `containing_item` will the grandparent, since trait impls can't have stability attached.
         fn doc_impl_item(
-            boring: &mut String,
-            interesting: &mut String,
+            boring: impl fmt::Write,
+            interesting: impl fmt::Write,
             cx: &Context<'_>,
             item: &clean::Item,
             parent: &clean::Item,
@@ -1652,7 +1672,7 @@ fn render_impl(
             is_default_item: bool,
             trait_: Option<&clean::Trait>,
             rendering_params: ImplRenderingParameters,
-        ) {
+        ) -> fmt::Result {
             let item_type = item.type_();
             let name = item.name.as_ref().unwrap();
 
@@ -1727,15 +1747,16 @@ fn render_impl(
                     );
                 }
             }
-            let w = if short_documented && trait_.is_some() { interesting } else { boring };
+            let mut w = if short_documented && trait_.is_some() {
+                Either::Left(interesting)
+            } else {
+                Either::Right(boring)
+            };
 
             let toggled = !doc_buffer.is_empty();
             if toggled {
                 let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
-                write_str(
-                    w,
-                    format_args!("<details class=\"toggle{method_toggle_class}\" open><summary>"),
-                );
+                write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>")?;
             }
             match &item.kind {
                 clean::MethodItem(..) | clean::RequiredMethodItem(_) => {
@@ -1750,172 +1771,151 @@ fn render_impl(
                                     .find(|item| item.name.map(|n| n == *name).unwrap_or(false))
                             })
                             .map(|item| format!("{}.{name}", item.type_()));
-                        write_str(
+                        write!(
                             w,
-                            format_args!(
-                                "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
+                            "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
                                 {}",
-                                render_rightside(cx, item, render_mode)
-                            ),
-                        );
+                            render_rightside(cx, item, render_mode)
+                        )?;
                         if trait_.is_some() {
                             // Anchors are only used on trait impls.
-                            write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">§</a>"));
+                            write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>")?;
                         }
-                        write_str(
+                        write!(
                             w,
-                            format_args!(
-                                "<h4 class=\"code-header\">{}</h4></section>",
-                                render_assoc_item(
-                                    item,
-                                    link.anchor(source_id.as_ref().unwrap_or(&id)),
-                                    ItemType::Impl,
-                                    cx,
-                                    render_mode,
-                                ),
+                            "<h4 class=\"code-header\">{}</h4></section>",
+                            render_assoc_item(
+                                item,
+                                link.anchor(source_id.as_ref().unwrap_or(&id)),
+                                ItemType::Impl,
+                                cx,
+                                render_mode,
                             ),
-                        );
+                        )?;
                     }
                 }
                 clean::RequiredAssocConstItem(generics, ty) => {
                     let source_id = format!("{item_type}.{name}");
                     let id = cx.derive_id(&source_id);
-                    write_str(
+                    write!(
                         w,
-                        format_args!(
-                            "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
+                        "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
                             {}",
-                            render_rightside(cx, item, render_mode)
-                        ),
-                    );
+                        render_rightside(cx, item, render_mode)
+                    )?;
                     if trait_.is_some() {
                         // Anchors are only used on trait impls.
-                        write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">§</a>"));
+                        write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>")?;
                     }
-                    write_str(
+                    write!(
                         w,
-                        format_args!(
-                            "<h4 class=\"code-header\">{}</h4></section>",
-                            assoc_const(
-                                item,
-                                generics,
-                                ty,
-                                AssocConstValue::None,
-                                link.anchor(if trait_.is_some() { &source_id } else { &id }),
-                                0,
-                                cx,
-                            )
+                        "<h4 class=\"code-header\">{}</h4></section>",
+                        assoc_const(
+                            item,
+                            generics,
+                            ty,
+                            AssocConstValue::None,
+                            link.anchor(if trait_.is_some() { &source_id } else { &id }),
+                            0,
+                            cx,
                         ),
-                    );
+                    )?;
                 }
                 clean::ProvidedAssocConstItem(ci) | clean::ImplAssocConstItem(ci) => {
                     let source_id = format!("{item_type}.{name}");
                     let id = cx.derive_id(&source_id);
-                    write_str(
+                    write!(
                         w,
-                        format_args!(
-                            "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
+                        "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
                             {}",
-                            render_rightside(cx, item, render_mode)
-                        ),
-                    );
+                        render_rightside(cx, item, render_mode),
+                    )?;
                     if trait_.is_some() {
                         // Anchors are only used on trait impls.
-                        write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">§</a>"));
+                        write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>")?;
                     }
-                    write_str(
+                    write!(
                         w,
-                        format_args!(
-                            "<h4 class=\"code-header\">{}</h4></section>",
-                            assoc_const(
-                                item,
-                                &ci.generics,
-                                &ci.type_,
-                                match item.kind {
-                                    clean::ProvidedAssocConstItem(_) =>
-                                        AssocConstValue::TraitDefault(&ci.kind),
-                                    clean::ImplAssocConstItem(_) => AssocConstValue::Impl(&ci.kind),
-                                    _ => unreachable!(),
-                                },
-                                link.anchor(if trait_.is_some() { &source_id } else { &id }),
-                                0,
-                                cx,
-                            )
+                        "<h4 class=\"code-header\">{}</h4></section>",
+                        assoc_const(
+                            item,
+                            &ci.generics,
+                            &ci.type_,
+                            match item.kind {
+                                clean::ProvidedAssocConstItem(_) =>
+                                    AssocConstValue::TraitDefault(&ci.kind),
+                                clean::ImplAssocConstItem(_) => AssocConstValue::Impl(&ci.kind),
+                                _ => unreachable!(),
+                            },
+                            link.anchor(if trait_.is_some() { &source_id } else { &id }),
+                            0,
+                            cx,
                         ),
-                    );
+                    )?;
                 }
                 clean::RequiredAssocTypeItem(generics, bounds) => {
                     let source_id = format!("{item_type}.{name}");
                     let id = cx.derive_id(&source_id);
-                    write_str(
+                    write!(
                         w,
-                        format_args!(
-                            "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
+                        "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
                             {}",
-                            render_rightside(cx, item, render_mode)
-                        ),
-                    );
+                        render_rightside(cx, item, render_mode),
+                    )?;
                     if trait_.is_some() {
                         // Anchors are only used on trait impls.
-                        write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">§</a>"));
+                        write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>")?;
                     }
-                    write_str(
+                    write!(
                         w,
-                        format_args!(
-                            "<h4 class=\"code-header\">{}</h4></section>",
-                            assoc_type(
-                                item,
-                                generics,
-                                bounds,
-                                None,
-                                link.anchor(if trait_.is_some() { &source_id } else { &id }),
-                                0,
-                                cx,
-                            )
+                        "<h4 class=\"code-header\">{}</h4></section>",
+                        assoc_type(
+                            item,
+                            generics,
+                            bounds,
+                            None,
+                            link.anchor(if trait_.is_some() { &source_id } else { &id }),
+                            0,
+                            cx,
                         ),
-                    );
+                    )?;
                 }
                 clean::AssocTypeItem(tydef, _bounds) => {
                     let source_id = format!("{item_type}.{name}");
                     let id = cx.derive_id(&source_id);
-                    write_str(
+                    write!(
                         w,
-                        format_args!(
-                            "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
+                        "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
                             {}",
-                            render_rightside(cx, item, render_mode)
-                        ),
-                    );
+                        render_rightside(cx, item, render_mode),
+                    )?;
                     if trait_.is_some() {
                         // Anchors are only used on trait impls.
-                        write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">§</a>"));
+                        write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>")?;
                     }
-                    write_str(
+                    write!(
                         w,
-                        format_args!(
-                            "<h4 class=\"code-header\">{}</h4></section>",
-                            assoc_type(
-                                item,
-                                &tydef.generics,
-                                &[], // intentionally leaving out bounds
-                                Some(tydef.item_type.as_ref().unwrap_or(&tydef.type_)),
-                                link.anchor(if trait_.is_some() { &source_id } else { &id }),
-                                0,
-                                cx,
-                            )
+                        "<h4 class=\"code-header\">{}</h4></section>",
+                        assoc_type(
+                            item,
+                            &tydef.generics,
+                            &[], // intentionally leaving out bounds
+                            Some(tydef.item_type.as_ref().unwrap_or(&tydef.type_)),
+                            link.anchor(if trait_.is_some() { &source_id } else { &id }),
+                            0,
+                            cx,
                         ),
-                    );
+                    )?;
                 }
-                clean::StrippedItem(..) => return,
+                clean::StrippedItem(..) => return Ok(()),
                 _ => panic!("can't make docs for trait item with name {:?}", item.name),
             }
 
-            w.push_str(&info_buffer);
+            w.write_str(&info_buffer)?;
             if toggled {
-                w.push_str("</summary>");
-                w.push_str(&doc_buffer);
-                w.push_str("</details>");
+                write!(w, "</summary>{doc_buffer}</details>")?;
             }
+            Ok(())
         }
 
         let mut impl_items = String::new();
@@ -1958,7 +1958,7 @@ fn render_impl(
                             false,
                             trait_,
                             rendering_params,
-                        );
+                        )?;
                     }
                     _ => {}
                 }
@@ -1976,7 +1976,7 @@ fn render_impl(
                     false,
                     trait_,
                     rendering_params,
-                );
+                )?;
             }
             for method in methods {
                 doc_impl_item(
@@ -1990,20 +1990,20 @@ fn render_impl(
                     false,
                     trait_,
                     rendering_params,
-                );
+                )?;
             }
         }
 
         fn render_default_items(
-            boring: &mut String,
-            interesting: &mut String,
+            mut boring: impl fmt::Write,
+            mut interesting: impl fmt::Write,
             cx: &Context<'_>,
             t: &clean::Trait,
             i: &clean::Impl,
             parent: &clean::Item,
             render_mode: RenderMode,
             rendering_params: ImplRenderingParameters,
-        ) {
+        ) -> fmt::Result {
             for trait_item in &t.items {
                 // Skip over any default trait items that are impossible to reference
                 // (e.g. if it has a `Self: Sized` bound on an unsized type).
@@ -2023,8 +2023,8 @@ fn render_impl(
                 let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_methods);
 
                 doc_impl_item(
-                    boring,
-                    interesting,
+                    &mut boring,
+                    &mut interesting,
                     cx,
                     trait_item,
                     parent,
@@ -2033,8 +2033,9 @@ fn render_impl(
                     true,
                     Some(t),
                     rendering_params,
-                );
+                )?;
             }
+            Ok(())
         }
 
         // If we've implemented a trait, then also emit documentation for all
@@ -2054,7 +2055,7 @@ fn render_impl(
                     &i.impl_item,
                     render_mode,
                     rendering_params,
-                );
+                )?;
             }
         }
         if render_mode == RenderMode::Normal {
@@ -2171,7 +2172,7 @@ fn render_rightside(
     })
 }
 
-pub(crate) fn render_impl_summary(
+fn render_impl_summary(
     cx: &Context<'_>,
     i: &Impl,
     parent: &clean::Item,
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 3c5c2ce1976..96847f13f65 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -2,7 +2,7 @@ use std::cmp::Ordering;
 use std::fmt::{self, Display, Write as _};
 use std::iter;
 
-use rinja::Template;
+use askama::Template;
 use rustc_abi::VariantIdx;
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_hir as hir;
@@ -37,7 +37,7 @@ use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
 use crate::html::render::{document_full, document_item_info};
 use crate::html::url_parts_builder::UrlPartsBuilder;
 
-/// Generates a Rinja template struct for rendering items with common methods.
+/// Generates an Askama template struct for rendering items with common methods.
 ///
 /// Usage:
 /// ```ignore (illustrative)
@@ -301,7 +301,7 @@ fn toggle_close(mut w: impl fmt::Write) {
     w.write_str("</details>").unwrap();
 }
 
-trait ItemTemplate<'a, 'cx: 'a>: rinja::Template + Display {
+trait ItemTemplate<'a, 'cx: 'a>: askama::Template + Display {
     fn item_and_cx(&self) -> (&'a clean::Item, &'a Context<'cx>);
 }
 
@@ -1867,7 +1867,7 @@ fn item_proc_macro(cx: &Context<'_>, it: &clean::Item, m: &clean::ProcMacro) ->
                     }
                 }
             }
-            Ok(())
+            fmt::Result::Ok(())
         })?;
         write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
     })
@@ -1944,7 +1944,7 @@ fn item_constant(
                     }
                 }
             }
-            Ok(())
+            Ok::<(), fmt::Error>(())
         })?;
 
         write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs
index 89ff61ecb03..cd0c9775f5c 100644
--- a/src/librustdoc/html/render/sidebar.rs
+++ b/src/librustdoc/html/render/sidebar.rs
@@ -1,7 +1,7 @@
 use std::borrow::Cow;
 use std::cmp::Ordering;
 
-use rinja::Template;
+use askama::Template;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::{DefIdMap, DefIdSet};
@@ -123,10 +123,10 @@ impl<'a> Link<'a> {
 pub(crate) mod filters {
     use std::fmt::{self, Display};
 
-    use rinja::filters::Safe;
+    use askama::filters::Safe;
 
     use crate::html::escape::EscapeBodyTextWithWbr;
-    pub(crate) fn wrapped<T>(v: T) -> rinja::Result<Safe<impl Display>>
+    pub(crate) fn wrapped<T>(v: T) -> askama::Result<Safe<impl Display>>
     where
         T: Display,
     {
diff --git a/src/librustdoc/html/render/tests.rs b/src/librustdoc/html/render/tests.rs
index 657cd3c82aa..327a30887b1 100644
--- a/src/librustdoc/html/render/tests.rs
+++ b/src/librustdoc/html/render/tests.rs
@@ -47,8 +47,7 @@ fn test_all_types_prints_header_once() {
     // Regression test for #82477
     let all_types = AllTypes::new();
 
-    let mut buffer = String::new();
-    all_types.print(&mut buffer);
+    let buffer = all_types.print().to_string();
 
     assert_eq!(1, buffer.matches("List of all items").count());
 }
diff --git a/src/librustdoc/html/render/type_layout.rs b/src/librustdoc/html/render/type_layout.rs
index a1ee5c8c548..fb1f0271c2a 100644
--- a/src/librustdoc/html/render/type_layout.rs
+++ b/src/librustdoc/html/render/type_layout.rs
@@ -1,6 +1,6 @@
 use std::fmt;
 
-use rinja::Template;
+use askama::Template;
 use rustc_abi::{Primitive, TagEncoding, Variants};
 use rustc_hir::def_id::DefId;
 use rustc_middle::span_bug;
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index cbbd4b01d83..095795c711d 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -3,7 +3,7 @@ use std::ffi::OsStr;
 use std::path::{Component, Path, PathBuf};
 use std::{fmt, fs};
 
-use rinja::Template;
+use askama::Template;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::ty::TyCtxt;
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 0ea4d8f1e39..74d23b3143f 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -1446,6 +1446,9 @@ so that we can apply CSS-filters to change the arrow color in themes */
 	align-items: center;
 	cursor: pointer;
 }
+.setting-check input {
+	flex-shrink: 0;
+}
 
 .setting-radio input:checked {
 	box-shadow: inset 0 0 0 3px var(--main-background-color);
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 4150c5609a9..a7ce2bf9048 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -1101,7 +1101,6 @@ function preLoadCss(cssUrl) {
         });
     }());
 
-    // @ts-expect-error
     window.rustdoc_add_line_numbers_to_examples = () => {
         // @ts-expect-error
         function generateLine(nb) {
@@ -1123,7 +1122,6 @@ function preLoadCss(cssUrl) {
         });
     };
 
-    // @ts-expect-error
     window.rustdoc_remove_line_numbers_from_examples = () => {
         onEachLazy(
             document.querySelectorAll(".rustdoc:not(.src) :not(.scraped-example) > .example-wrap"),
@@ -1132,7 +1130,6 @@ function preLoadCss(cssUrl) {
     };
 
     if (getSettingValue("line-numbers") === "true") {
-        // @ts-expect-error
         window.rustdoc_add_line_numbers_to_examples();
     }
 
@@ -1596,7 +1593,7 @@ function preLoadCss(cssUrl) {
     /**
      * Hide popover menus, clickable tooltips, and the sidebar (if applicable).
      *
-     * Pass "true" to reset focus for tooltip popovers.
+     * Pass `true` to reset focus for tooltip popovers.
      */
     window.hideAllModals = switchFocus => {
         hideSidebar();
diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts
index 91a58fab86e..0d2e19e019f 100644
--- a/src/librustdoc/html/static/js/rustdoc.d.ts
+++ b/src/librustdoc/html/static/js/rustdoc.d.ts
@@ -30,6 +30,8 @@ declare global {
         currentCrate: string|null;
         /**
          * Hide popovers, tooltips, or the mobile sidebar.
+         *
+         * Pass `true` to reset focus for tooltip popovers.
          */
         hideAllModals: function(boolean),
         /**
@@ -78,6 +80,8 @@ declare global {
         pending_implementors?: rustdoc.Implementors,
         register_type_impls?: function(rustdoc.TypeImpls): void,
         pending_type_impls?: rustdoc.TypeImpls,
+        rustdoc_add_line_numbers_to_examples?: function(),
+        rustdoc_remove_line_numbers_from_examples?: function(),
     }
     interface HTMLElement {
         /** Used by the popover tooltip code. */
@@ -477,4 +481,14 @@ declare namespace rustdoc {
      * is a tuple of (filename, subdirs, filenames).
      */
     type Dir = [string, rustdoc.Dir[], string[]]
+
+    /**
+     * Indivitual setting object, used in `settings.js`
+     */
+    interface Setting {
+        js_name: string,
+        name: string,
+        options?: string[],
+        default: string | boolean,
+    }
 }
diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js
index 5f1bbd27328..2430b5829b2 100644
--- a/src/librustdoc/html/static/js/settings.js
+++ b/src/librustdoc/html/static/js/settings.js
@@ -1,22 +1,39 @@
 // Local js definitions:
 /* global getSettingValue, updateLocalStorage, updateTheme */
 /* global addClass, removeClass, onEach, onEachLazy */
-/* global MAIN_ID, getVar, getSettingsButton, getHelpButton */
-
-// Eventually fix this.
-// @ts-nocheck
+/* global MAIN_ID, getVar, getSettingsButton, getHelpButton, nonnull */
 
 "use strict";
 
 (function() {
     const isSettingsPage = window.location.pathname.endsWith("/settings.html");
 
+    /**
+     * @param {Element} elem
+     * @param {EventTarget|null} target
+     */
+    function elemContainsTarget(elem, target) {
+        if (target instanceof Node) {
+            return elem.contains(target);
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * @overload {"theme"|"preferred-dark-theme"|"preferred-light-theme"}
+     * @param {string} settingName
+     * @param {string} value
+     * @returns
+     * @param {string} settingName
+     * @param {string|boolean} value
+     */
     function changeSetting(settingName, value) {
         if (settingName === "theme") {
             const useSystem = value === "system preference" ? "true" : "false";
             updateLocalStorage("use-system-theme", useSystem);
         }
-        updateLocalStorage(settingName, value);
+        updateLocalStorage(settingName, "" + value);
 
         switch (settingName) {
             case "theme":
@@ -27,9 +44,15 @@
                 break;
             case "line-numbers":
                 if (value === true) {
-                    window.rustdoc_add_line_numbers_to_examples();
+                    const f = window.rustdoc_add_line_numbers_to_examples;
+                    if (f !== undefined) {
+                        f();
+                    }
                 } else {
-                    window.rustdoc_remove_line_numbers_from_examples();
+                    const f = window.rustdoc_remove_line_numbers_from_examples;
+                    if (f !== undefined) {
+                        f();
+                    }
                 }
                 break;
             case "hide-sidebar":
@@ -89,6 +112,9 @@
         }
     }
 
+    /**
+     * @param {HTMLElement} settingsElement
+     */
     function setEvents(settingsElement) {
         updateLightAndDark();
         onEachLazy(settingsElement.querySelectorAll("input[type=\"checkbox\"]"), toggle => {
@@ -101,23 +127,27 @@
                 changeSetting(toggle.id, toggle.checked);
             };
         });
-        onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"), elem => {
-            const settingId = elem.name;
-            let settingValue = getSettingValue(settingId);
-            if (settingId === "theme") {
-                const useSystem = getSettingValue("use-system-theme");
-                if (useSystem === "true" || settingValue === null) {
-                    // "light" is the default theme
-                    settingValue = useSystem === "false" ? "light" : "system preference";
+        onEachLazy(
+            settingsElement.querySelectorAll("input[type=\"radio\"]"),
+            /** @param {HTMLInputElement} elem */
+            elem => {
+                const settingId = elem.name;
+                let settingValue = getSettingValue(settingId);
+                if (settingId === "theme") {
+                    const useSystem = getSettingValue("use-system-theme");
+                    if (useSystem === "true" || settingValue === null) {
+                        // "light" is the default theme
+                        settingValue = useSystem === "false" ? "light" : "system preference";
+                    }
                 }
-            }
-            if (settingValue !== null && settingValue !== "null") {
-                elem.checked = settingValue === elem.value;
-            }
-            elem.addEventListener("change", ev => {
-                changeSetting(ev.target.name, ev.target.value);
-            });
-        });
+                if (settingValue !== null && settingValue !== "null") {
+                    elem.checked = settingValue === elem.value;
+                }
+                elem.addEventListener("change", () => {
+                    changeSetting(elem.name, elem.value);
+                });
+            },
+        );
     }
 
     /**
@@ -125,7 +155,7 @@
      * as argument which describes each setting and how to render it. It returns a string
      * representing the raw HTML.
      *
-     * @param {Array<Object>} settings
+     * @param {Array<rustdoc.Setting>} settings
      *
      * @return {string}
      */
@@ -133,11 +163,6 @@
         let output = "";
 
         for (const setting of settings) {
-            if (setting === "hr") {
-                output += "<hr>";
-                continue;
-            }
-
             const js_data_name = setting["js_name"];
             const setting_name = setting["name"];
 
@@ -182,7 +207,9 @@
      * @return {HTMLElement}
      */
     function buildSettingsPage() {
-        const theme_names = getVar("themes").split(",").filter(t => t);
+        const theme_list = getVar("themes");
+        const theme_names = (theme_list === null ? "" : theme_list)
+              .split(",").filter(t => t);
         theme_names.push("light", "dark", "ayu");
 
         const settings = [
@@ -272,10 +299,16 @@
         el.innerHTML = innerHTML;
 
         if (isSettingsPage) {
-            document.getElementById(MAIN_ID).appendChild(el);
+            const mainElem = document.getElementById(MAIN_ID);
+            if (mainElem !== null) {
+                mainElem.appendChild(el);
+            }
         } else {
             el.setAttribute("tabindex", "-1");
-            getSettingsButton().appendChild(el);
+            const settingsBtn = getSettingsButton();
+            if (settingsBtn !== null) {
+                settingsBtn.appendChild(el);
+            }
         }
         return el;
     }
@@ -293,34 +326,44 @@
         });
     }
 
+    /**
+     * @param {FocusEvent} event
+     */
     function settingsBlurHandler(event) {
-        if (!getHelpButton().contains(document.activeElement) &&
-            !getHelpButton().contains(event.relatedTarget) &&
-            !getSettingsButton().contains(document.activeElement) &&
-            !getSettingsButton().contains(event.relatedTarget)
-        ) {
+        const helpBtn = getHelpButton();
+        const settingsBtn = getSettingsButton();
+        const helpUnfocused = helpBtn === null ||
+              (!helpBtn.contains(document.activeElement) &&
+               !elemContainsTarget(helpBtn, event.relatedTarget));
+        const settingsUnfocused = settingsBtn === null ||
+              (!settingsBtn.contains(document.activeElement) &&
+               !elemContainsTarget(settingsBtn, event.relatedTarget));
+        if (helpUnfocused && settingsUnfocused) {
             window.hidePopoverMenus();
         }
     }
 
     if (!isSettingsPage) {
         // We replace the existing "onclick" callback.
-        const settingsButton = getSettingsButton();
-        const settingsMenu = document.getElementById("settings");
+        // These elements must exist, as (outside of the settings page)
+        // `settings.js` is only loaded after the settings button is clicked.
+        const settingsButton = nonnull(getSettingsButton());
+        const settingsMenu = nonnull(document.getElementById("settings"));
         settingsButton.onclick = event => {
-            if (settingsMenu.contains(event.target)) {
+            if (elemContainsTarget(settingsMenu, event.target)) {
                 return;
             }
             event.preventDefault();
             const shouldDisplaySettings = settingsMenu.style.display === "none";
 
-            window.hideAllModals();
+            window.hideAllModals(false);
             if (shouldDisplaySettings) {
                 displaySettings();
             }
         };
         settingsButton.onblur = settingsBlurHandler;
-        settingsButton.querySelector("a").onblur = settingsBlurHandler;
+        // the settings button should always have a link in it
+        nonnull(settingsButton.querySelector("a")).onblur = settingsBlurHandler;
         onEachLazy(settingsMenu.querySelectorAll("input"), el => {
             el.onblur = settingsBlurHandler;
         });
diff --git a/src/librustdoc/html/templates/STYLE.md b/src/librustdoc/html/templates/STYLE.md
index 32bacb11475..12c2553cffd 100644
--- a/src/librustdoc/html/templates/STYLE.md
+++ b/src/librustdoc/html/templates/STYLE.md
@@ -1,13 +1,13 @@
 # Style for Templates
 
-This directory has templates in the [Rinja templating language][rinjadoc], which is very
+This directory has templates in the [Askama templating language][askamadoc], which is very
 similar to [Jinja2][jinjadoc].
 
 [jinjadoc]: https://jinja.palletsprojects.com/en/3.1.x/templates/
-[rinjadoc]: https://docs.rs/rinja/latest/rinja/
+[askamadoc]: https://docs.rs/askama/latest/askama/
 
 We want our rendered output to have as little unnecessary whitespace as
-possible, so that pages load quickly. To achieve that we use Rinja's
+possible, so that pages load quickly. To achieve that we use Askama's
 [whitespace control] features. By default, whitespace characters are removed
 around jinja tags (`{% %}` for example). At the end of most lines, we put an
 empty comment tag: `{# #}`. This causes all whitespace between the end of the
@@ -18,7 +18,7 @@ remove following whitespace but not preceding. We also use the whitespace
 control characters in most instances of tags with control flow, for example
 `{% if foo %}`.
 
-[whitespace control]: https://rinja.readthedocs.io/en/stable/configuration.html#whitespace-control
+[whitespace control]: https://askama.readthedocs.io/en/stable/configuration.html#whitespace-control
 
 We want our templates to be readable, so we use indentation and newlines
 liberally. We indent by four spaces after opening an HTML tag _or_ a Jinja
@@ -26,11 +26,11 @@ tag. In most cases an HTML tag should be followed by a newline, but if the
 tag has simple contents and fits with its close tag on a single line, the
 contents don't necessarily need a new line.
 
-Rinja templates support quite sophisticated control flow. To keep our templates
+Askama templates support quite sophisticated control flow. To keep our templates
 simple and understandable, we use only a subset: `if` and `for`. In particular
-we avoid [assignments in the template logic][assignments] and [Rinja
+we avoid [assignments in the template logic][assignments] and [Askama
 macros][macros]. This also may make things easier if we switch to a different
 Jinja-style template system in the future.
 
-[assignments]: https://rinja.readthedocs.io/en/stable/template_syntax.html#assignments
-[macros]: https://rinja.readthedocs.io/en/stable/template_syntax.html#macros
+[assignments]: https://askama.readthedocs.io/en/stable/template_syntax.html#assignments
+[macros]: https://askama.readthedocs.io/en/stable/template_syntax.html#macros
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index f8f670f575b..761282bde7c 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -5,7 +5,7 @@ use std::ops;
 
 use rustc_hir as hir;
 use rustc_lint::builtin::MISSING_DOCS;
-use rustc_middle::lint::LintLevelSource;
+use rustc_middle::lint::{LevelAndSource, LintLevelSource};
 use rustc_session::lint;
 use rustc_span::FileName;
 use serde::Serialize;
@@ -216,7 +216,8 @@ impl DocVisitor<'_> for CoverageCalculator<'_, '_> {
 
                 let has_doc_example = tests.found_tests != 0;
                 let hir_id = DocContext::as_local_hir_id(self.ctx.tcx, i.item_id).unwrap();
-                let (level, source) = self.ctx.tcx.lint_level_at_node(MISSING_DOCS, hir_id);
+                let LevelAndSource { level, src, .. } =
+                    self.ctx.tcx.lint_level_at_node(MISSING_DOCS, hir_id);
 
                 // In case we have:
                 //
@@ -251,7 +252,7 @@ impl DocVisitor<'_> for CoverageCalculator<'_, '_> {
                 // unless the user had an explicit `allow`.
                 //
                 let should_have_docs = !should_be_ignored
-                    && (level != lint::Level::Allow || matches!(source, LintLevelSource::Default));
+                    && (level != lint::Level::Allow || matches!(src, LintLevelSource::Default));
 
                 if let Some(span) = i.span(self.ctx.tcx) {
                     let filename = span.filename(self.ctx.sess());
diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs
index 0fefd13f763..70dbb944d4c 100644
--- a/src/librustdoc/passes/check_doc_test_visibility.rs
+++ b/src/librustdoc/passes/check_doc_test_visibility.rs
@@ -6,7 +6,7 @@
 //! - PRIVATE_DOC_TESTS: this lint is **STABLE** and looks for private items with doctests.
 
 use rustc_hir as hir;
-use rustc_middle::lint::LintLevelSource;
+use rustc_middle::lint::{LevelAndSource, LintLevelSource};
 use rustc_session::lint;
 use tracing::debug;
 
@@ -107,11 +107,11 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -
     {
         return false;
     }
-    let (level, source) = cx.tcx.lint_level_at_node(
+    let LevelAndSource { level, src, .. } = cx.tcx.lint_level_at_node(
         crate::lint::MISSING_DOC_CODE_EXAMPLES,
         cx.tcx.local_def_id_to_hir_id(def_id),
     );
-    level != lint::Level::Allow || matches!(source, LintLevelSource::Default)
+    level != lint::Level::Allow || matches!(src, LintLevelSource::Default)
 }
 
 pub(crate) fn look_for_tests(cx: &DocContext<'_>, dox: &str, item: &Item) {
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index fdbb792d25d..297597b3dea 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -60,7 +60,7 @@ fn filter_assoc_items_by_name_and_namespace(
     ns: Namespace,
 ) -> impl Iterator<Item = &ty::AssocItem> {
     tcx.associated_items(assoc_items_of).filter_by_name_unhygienic(ident.name).filter(move |item| {
-        item.kind.namespace() == ns && tcx.hygienic_eq(ident, item.ident(tcx), assoc_items_of)
+        item.namespace() == ns && tcx.hygienic_eq(ident, item.ident(tcx), assoc_items_of)
     })
 }
 
@@ -743,7 +743,7 @@ impl<'tcx> LinkCollector<'_, 'tcx> {
                 ns,
             )
             .map(|item| {
-                let res = Res::Def(item.kind.as_def_kind(), item.def_id);
+                let res = Res::Def(item.as_def_kind(), item.def_id);
                 (res, item.def_id)
             })
             .collect::<Vec<_>>(),
diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs
index bcdca862862..692ce21d6cf 100644
--- a/src/librustdoc/passes/strip_hidden.rs
+++ b/src/librustdoc/passes/strip_hidden.rs
@@ -91,19 +91,21 @@ impl DocFolder for Stripper<'_, '_> {
 
         if let clean::ImportItem(clean::Import { source, .. }) = &i.kind
             && let Some(source_did) = source.did
-            && let Some(import_def_id) = i.def_id().and_then(|def_id| def_id.as_local())
         {
-            let reexports = reexport_chain(self.tcx, import_def_id, source_did);
+            if self.tcx.is_doc_hidden(source_did) {
+                return None;
+            } else if let Some(import_def_id) = i.def_id().and_then(|def_id| def_id.as_local()) {
+                let reexports = reexport_chain(self.tcx, import_def_id, source_did);
 
-            // Check if any reexport in the chain has a hidden source
-            let has_hidden_source = reexports
-                .iter()
-                .filter_map(|reexport| reexport.id())
-                .any(|reexport_did| self.tcx.is_doc_hidden(reexport_did))
-                || self.tcx.is_doc_hidden(source_did);
+                // Check if any reexport in the chain has a hidden source
+                let has_hidden_source = reexports
+                    .iter()
+                    .filter_map(|reexport| reexport.id())
+                    .any(|reexport_did| self.tcx.is_doc_hidden(reexport_did));
 
-            if has_hidden_source {
-                return None;
+                if has_hidden_source {
+                    return None;
+                }
             }
         }
 
diff --git a/src/stage0 b/src/stage0
index 9d6a08d378d..6e86501a72a 100644
--- a/src/stage0
+++ b/src/stage0
@@ -14,468 +14,466 @@ nightly_branch=master
 # All changes below this comment will be overridden the next time the
 # tool is executed.
 
-compiler_date=2025-02-18
+compiler_date=2025-04-02
 compiler_version=beta
-rustfmt_date=2025-02-18
+rustfmt_date=2025-04-02
 rustfmt_version=nightly
 
-dist/2025-02-18/rustc-beta-aarch64-apple-darwin.tar.gz=1b51ca064350d8b15c7ab6c8ec996a497e912dc237cafc2c205066fc6416e0ff
-dist/2025-02-18/rustc-beta-aarch64-apple-darwin.tar.xz=e4b71f6456d9e62ada6909254606da7f6681f3da0f5bc7d2c3d5c387fea35743
-dist/2025-02-18/rustc-beta-aarch64-pc-windows-msvc.tar.gz=1ff70a5bd238d959d806c3b471a5b03c6cde784944a96a585e0ae0837d2a9c92
-dist/2025-02-18/rustc-beta-aarch64-pc-windows-msvc.tar.xz=5017b351bb90a08041757eae61386b224ec0161c5734293184a87d8903f30098
-dist/2025-02-18/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=8a58b6cc4577615efc76bb9472229098d6f938c1f051ea540409e9dc812dbd8f
-dist/2025-02-18/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=330e217dbd1c507c8706aef5fbd0baf9584495445743f38668cdc962adfb125e
-dist/2025-02-18/rustc-beta-aarch64-unknown-linux-musl.tar.gz=4060ec54281975880a9819b815120d6a450e4c31ddf1136ecce348e28875d50d
-dist/2025-02-18/rustc-beta-aarch64-unknown-linux-musl.tar.xz=0f92b9267a55ac0c764cde63b8cbc8a0a317f7e0817185d380fc2aa35a933687
-dist/2025-02-18/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=4e989e00725e7cfb08ea834c74ec6dd352eda74c13218f7da423ed598af9f9df
-dist/2025-02-18/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=b06181daf8842c2e544e5d54169f9bbfc70ee76115495de033ac4e341617a588
-dist/2025-02-18/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=93fe2efcde1032ad636ef509a73168f0ab7fadbca699a27e2882b3832539e8fa
-dist/2025-02-18/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=b49d0256381c928785035578e5b7624c37ba732ea7aefca37dbb66b5162c8090
-dist/2025-02-18/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=56fd36c20d78085f39f0df40f15f7694e8744714104539865b9c3d7b06d47e2f
-dist/2025-02-18/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=86587bea60c2b8a114ab33fe65a7152fcf8e1dcca14550712dca72af9fd65674
-dist/2025-02-18/rustc-beta-i686-pc-windows-gnu.tar.gz=32c95c78b223efea2ee8e02fbe3a58ac753ce9284e792bc87feaa051fcff5687
-dist/2025-02-18/rustc-beta-i686-pc-windows-gnu.tar.xz=d2e623f11aee7e81eceb6947e3f7150bfd727eb2f527e4abc6b10d3322959802
-dist/2025-02-18/rustc-beta-i686-pc-windows-msvc.tar.gz=f7ffd07eb2b5e83df513c6a313e28003e3ce923778583e78da9efbb5e62405dc
-dist/2025-02-18/rustc-beta-i686-pc-windows-msvc.tar.xz=cd2e61b548a6849b17183fcacb2ac8f94955d893be439793580c39080feb28be
-dist/2025-02-18/rustc-beta-i686-unknown-linux-gnu.tar.gz=fedeca202c1651fe4b15cfc411365ecf016376b3cc7c772d2e0d739e0ec02dc6
-dist/2025-02-18/rustc-beta-i686-unknown-linux-gnu.tar.xz=6389f10e2328bdfa81ef1f34406bb4ec8bcb6dcf64d39c95946d32c9fee7f0b7
-dist/2025-02-18/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=21b565bbaacc2be5d066c5d0c49b7c0f5b0bd24690ca35e9c88e6ec91846f744
-dist/2025-02-18/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=4a728e3ec41834775f0b288cdca5ae152314edcaf20d7ea46ea62fab1b9ef327
-dist/2025-02-18/rustc-beta-loongarch64-unknown-linux-musl.tar.gz=0a72f650aa70708f9a72886ea33b7a2e3ffe2a6e2cbcb1d2248f3d9eca74a9d4
-dist/2025-02-18/rustc-beta-loongarch64-unknown-linux-musl.tar.xz=877c3c447f4c25068f70bd7d6dd5078d75b0c194777b2f8a9311a66fc6eda701
-dist/2025-02-18/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=67af5e05ab0a367d3f76c0656823b530a23fb26d9c86db2b433684b9191b8881
-dist/2025-02-18/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=2da086d39eaa000ba629ee15bec740db57039ca3e5c7c55feb9cb9ca6d39c785
-dist/2025-02-18/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=b079df9a3e5be95a755d22f5ecf3ddeb43f94d96eaa3985770ae98ad0e7e15bb
-dist/2025-02-18/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=916fe3b67094bb351320371de9587f01bb65f9b9aed2c7aff7930e499822b660
-dist/2025-02-18/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=356e3173c960aadfb91dcb607a26647895fb1ae11a7cb596b019c71c6dd808e7
-dist/2025-02-18/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=9115c4c85d8c4b5254df41a5d3f55733648ba282711e18a692ee100ed13fb550
-dist/2025-02-18/rustc-beta-powerpc64le-unknown-linux-musl.tar.gz=b8a267f9ca2d23385c529924782f633b6b9f66b50cda5986eff91c223d715307
-dist/2025-02-18/rustc-beta-powerpc64le-unknown-linux-musl.tar.xz=84e65fc1d4282d737b6d0b1aaa1c2abd395af215983eb5b3700e925ca6ba3bc3
-dist/2025-02-18/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=19b1d8618edb5d3a6cf620c814f6b76a462bc965f4aac2cde7aca5849b92cac9
-dist/2025-02-18/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=9914408b5590fe7c43b2aa10c261bb5162b024e396c625b06546564a5eaddb89
-dist/2025-02-18/rustc-beta-s390x-unknown-linux-gnu.tar.gz=37ac73ea85f43a4859d8c4526cb9480e69bcaa778e842128852c8b21c6db6b45
-dist/2025-02-18/rustc-beta-s390x-unknown-linux-gnu.tar.xz=af1cab661b26cab1ade53f12ec08d13d60a74c2f370d9d3617154e0f01cb3719
-dist/2025-02-18/rustc-beta-x86_64-apple-darwin.tar.gz=aa9999ad56f8968e3e0f5417661ff42fbd1bd482a649d1a8c01d6ba5a6e78a72
-dist/2025-02-18/rustc-beta-x86_64-apple-darwin.tar.xz=bfd09bf8db9bbd7557df3f206207631cc4b10d59d0cf6b072e610646b5c7fa4a
-dist/2025-02-18/rustc-beta-x86_64-pc-windows-gnu.tar.gz=dabab346a003a5b13265da6bab96fc703c34f728c852092bec4cf08d13daeadc
-dist/2025-02-18/rustc-beta-x86_64-pc-windows-gnu.tar.xz=c2252dea69c8dcf6ba0213da8b05b8d9173676fb7448cde684da7b56d2c52577
-dist/2025-02-18/rustc-beta-x86_64-pc-windows-msvc.tar.gz=9ae9c3cb963872b2ef02650bcec15906e0b5e89cc6d3bee0aadfffcec7a1e6df
-dist/2025-02-18/rustc-beta-x86_64-pc-windows-msvc.tar.xz=bcbf75c92e9afe6b25bbde275bd38c3cdeda6324baf5b8c99173ca5738760a7f
-dist/2025-02-18/rustc-beta-x86_64-unknown-freebsd.tar.gz=5313d0780f6a9587e809da0f1ffc973721afad88a0ef8fb83005c383d79229d8
-dist/2025-02-18/rustc-beta-x86_64-unknown-freebsd.tar.xz=52ab3212d64b56a8da207fe976cbc8d266e962a61c742e6069137b10ff25c3c1
-dist/2025-02-18/rustc-beta-x86_64-unknown-illumos.tar.gz=527f839ddedc7bdff48527a276d3d7f64d475dd815b81c6664f1ce25668e0ce4
-dist/2025-02-18/rustc-beta-x86_64-unknown-illumos.tar.xz=3861d9928983a415cd44e5dc50a99af948fac392adfb6c2147b14fb98dd08890
-dist/2025-02-18/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=0054d14cf00b25cfbcb2a1560887c825f703223312ca9cdd0ad51076bf54a3cc
-dist/2025-02-18/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=75a9d69d13e50bb22ec721f9c64d08282d76f285482b285bb61bacabeecd710c
-dist/2025-02-18/rustc-beta-x86_64-unknown-linux-musl.tar.gz=305765ca6a413ea86360b970bd062a19f6bc52756551af43d74920fc2a021d95
-dist/2025-02-18/rustc-beta-x86_64-unknown-linux-musl.tar.xz=c7230b578a97fb234ac106c7333615074b9a7a8abc1422f149ad613c2af28134
-dist/2025-02-18/rustc-beta-x86_64-unknown-netbsd.tar.gz=881bd9b260b2c7838ea1b4de2cd6baf2ff4d317e0c159faba1a683c4c32ba267
-dist/2025-02-18/rustc-beta-x86_64-unknown-netbsd.tar.xz=0c4f2cc0bafbf8b41b257e851870b64d3b5fc112f02227f561c645dc439c96db
-dist/2025-02-18/rust-std-beta-aarch64-apple-darwin.tar.gz=958434edfc07bf6d10da3d41f01d1511b28d1178423a78bff2f60cd10046dbca
-dist/2025-02-18/rust-std-beta-aarch64-apple-darwin.tar.xz=80043af05fb96c497bce55063f2733e37f243f85084f9aa60ab504d7c15c5cce
-dist/2025-02-18/rust-std-beta-aarch64-apple-ios.tar.gz=509aa8803b29ccbb97a1a8c12e2ca6b27310d5af313650c7afff45ab1843106a
-dist/2025-02-18/rust-std-beta-aarch64-apple-ios.tar.xz=f0f05dafc9a3277b075023bb449675946706307f769590c065cb53ae615708d9
-dist/2025-02-18/rust-std-beta-aarch64-apple-ios-macabi.tar.gz=c37c0aee56c5858f91fb5aa60df28cc92649d4884d5edde57eb6690f494ba5f5
-dist/2025-02-18/rust-std-beta-aarch64-apple-ios-macabi.tar.xz=e5120697e4a118824fdebf6d2a644f8f338bb83e209303fc684095b8f6b4ab1c
-dist/2025-02-18/rust-std-beta-aarch64-apple-ios-sim.tar.gz=d5b851917a3f57703378596828e92068c28e00fe0b02331891737c2fc697b5ff
-dist/2025-02-18/rust-std-beta-aarch64-apple-ios-sim.tar.xz=ef33164320931007db65f4915b533e5078a7279a7a134fc80045751a5198834a
-dist/2025-02-18/rust-std-beta-aarch64-linux-android.tar.gz=4b94607d7c09b4f0f85236fb2237f1859150e12745ee2020cb134db904c1e05b
-dist/2025-02-18/rust-std-beta-aarch64-linux-android.tar.xz=3aa7807ef9da83e1a4deebe4a7085e4df1b60edd4e9f237870f827073100d09c
-dist/2025-02-18/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=2d4c8a5a400c35443228087f8203f320253299a5018c1b92526f99023581c3e9
-dist/2025-02-18/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=df8741055b3d4f7eeedec9e0101a1c184a37ffb75b2d4474bfbca577300355f2
-dist/2025-02-18/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=8db9c07d4b68018cd3c67be1e7bc496078dfa8a6852a35c449db5ba19f6bf0df
-dist/2025-02-18/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=f112e3d51013ceff37e8c05d80c3605b76ddec8e55474d55815b4860f96febc8
-dist/2025-02-18/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=2bb6d934225823c2dcdb86dca91dd8e488f69b238b283607f75abe9b5de46486
-dist/2025-02-18/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=99036fde94fe0cb3ab2d2f48cd9f9bbb4d2fa784f1bd21afaa71b032cd95b069
-dist/2025-02-18/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=c49fee34a02f5d3fe4e03ed7da90e045f7967c3e2e8f7a30804f4da5d535225c
-dist/2025-02-18/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=88170a13f9448b9671d252f0315aed94b6324716230db7307061d4890cfda70a
-dist/2025-02-18/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=a5e7442d722f6742fd0436d3c7d75738bc6cbd936f3399190086a88ef311e34e
-dist/2025-02-18/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=5d07a95e3203ebe98eed1b271a2e6ae44bead53e7bda019a8d256c8553c21bd1
-dist/2025-02-18/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=0af6b8fc7f46641d4de61ada9bc9ff01af7775d727121267177fa4c43cc9ed7b
-dist/2025-02-18/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=fd68b34e7aba25d8a834c018febbde6c3de7d967e014a738681642f41ec61603
-dist/2025-02-18/rust-std-beta-aarch64-unknown-none.tar.gz=46025b0892498de8e311be7bd6df261065f80a70720cb9285062161a30af5d76
-dist/2025-02-18/rust-std-beta-aarch64-unknown-none.tar.xz=b4cbf42364270c158d801ac7d4b6cfd7bf1f5f9e74a3044e6d959f1971f5bc34
-dist/2025-02-18/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=ae2a5c63cce6ce237c81ae78cabc6e1e0634c956789c2e2f39e3a6c0d864636f
-dist/2025-02-18/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=6bba5069c89d9a0d9a2013715814fb55ebcd77b342ed0dfc72115a18367c5e8c
-dist/2025-02-18/rust-std-beta-aarch64-unknown-uefi.tar.gz=0bef07ceece7523d6f41f1d640569c52ebe8a6b97b35da84240d873fd68250da
-dist/2025-02-18/rust-std-beta-aarch64-unknown-uefi.tar.xz=cff8b58e158786cee1a719552fb97cb2cd3a12b541641437809428a65eed42fa
-dist/2025-02-18/rust-std-beta-arm-linux-androideabi.tar.gz=a34fbf0d01cea60876a6d0aa4ee96587a5e31b6d4f84aa7c1ba5b7fed261b639
-dist/2025-02-18/rust-std-beta-arm-linux-androideabi.tar.xz=7d72d638f5984726fb4a61e81671d9557d0a9a876bf5bbf39b2df3c9983d2962
-dist/2025-02-18/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=9ef3aa1bcbe1a18658bd16359cbf3e94ae1b07f65bd5c69ffbfa964ad845baf5
-dist/2025-02-18/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=93020195c2ce07204179e2d2f900953707e341a71d9371551c4a727afc58378e
-dist/2025-02-18/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=5b0a4c4831534de85a5ba5b0149bbd824ca83648bf66babe5dbf13291b06e03d
-dist/2025-02-18/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=60f1ff95cc88330b6c9741520c02ec845e7b14943f2927091a9110b7fb1c4305
-dist/2025-02-18/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=0f254a943b6e56873d2ab84e8a93fa7a3ab723df5a7926faeadae4696ed06121
-dist/2025-02-18/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=0c682e7cbba8463682a0a20785ff7fd331d2bc7a32c0cf86b8159897fc5c5ee7
-dist/2025-02-18/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=6c5be45f79035f57ac41fd209f6e7d4439cab5acaa766f7bf001b24196411b1e
-dist/2025-02-18/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=bf25eb6650ad27377414d53af6857133a539530c841cf96e3cae4406bf4ad485
-dist/2025-02-18/rust-std-beta-arm64ec-pc-windows-msvc.tar.gz=39ec7fd0ecf47b36c6badc1fc71f1290e99d2edfa9d7cfa72446fbb32ba9c8b0
-dist/2025-02-18/rust-std-beta-arm64ec-pc-windows-msvc.tar.xz=f1d578e9251d95c94c20e3ee7888993ec7ea3d967a880f89963df7bea0bbe93b
-dist/2025-02-18/rust-std-beta-armebv7r-none-eabi.tar.gz=3990bce70402da79a27fd0f4adb169e4e9faf617bdbca2676bc41d9f85845dd7
-dist/2025-02-18/rust-std-beta-armebv7r-none-eabi.tar.xz=ac944400a3da94e32d7010e10b30879bbb5da456d3d54dfd0efc792884b035de
-dist/2025-02-18/rust-std-beta-armebv7r-none-eabihf.tar.gz=1196e2ae338b325ceb89edaab8b165478ec481270a7ce4c65f47f45d76e7b33b
-dist/2025-02-18/rust-std-beta-armebv7r-none-eabihf.tar.xz=fead57620d21252c958020e340fc793102d177f76fd90b3936eaf3a22a3b87c9
-dist/2025-02-18/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=e5e81e1501554c2b28745c4d905bbe50f909dce3b7806f6010a9d48cc528304e
-dist/2025-02-18/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=d3c9513cdb058685848de3d7864a7fa5a9b1e45f779a7ecf447ac7faae652772
-dist/2025-02-18/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=6ca5598fbdbf77bcf971e62d5b3f486e25d01e95773670bdc600448f29b68a09
-dist/2025-02-18/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=7e0a8798586538c4b322b58b9e1ac90e27dea4a0b5b750873f90b8ec9dcdbe2e
-dist/2025-02-18/rust-std-beta-armv7-linux-androideabi.tar.gz=cbd81d4f949248c0c48a60545648a384aa321ee5f590f52d50e8d3639a649745
-dist/2025-02-18/rust-std-beta-armv7-linux-androideabi.tar.xz=75216a970ba5a023717dbbd45b5a1a90ff9533f25deca241c11ebce80dc6229e
-dist/2025-02-18/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=5acf37dc6035d3d83d003d70d3db3c196b20d461a70385e8e5d545be1f4392b4
-dist/2025-02-18/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=8c75b0c815465126d6c7516883c478c78fc83cfb294bd5b9387d5bad65c9810f
-dist/2025-02-18/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=733fca96e3d6dd232c746a6034bd7cc864f06bfce3d5da3bfd72c5ca4cea221d
-dist/2025-02-18/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=e9ef142105d0073bf070a6de74e7173fbc09f3f22fd50eef0fea8ab6cf0ab4d7
-dist/2025-02-18/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=13f2b55f297628bea201f3caaae0178f0d898c67a696d4b60a37c3ba5af0582b
-dist/2025-02-18/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=455605ff7e88d69052a4b3798ba27a673807ac1be197a8ac9e57497b5bac1661
-dist/2025-02-18/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=5b4b8eae2d86baeb470ad2a143f5d91f0dedeb225607189d9d0f8c8115e5251f
-dist/2025-02-18/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=fd36a0f0a001436195eacdb52baee2462c43a1f9899b2e01ed60019f8285a95d
-dist/2025-02-18/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=093900dfc07c4c4f59bd84aa8e9b505890cd8736a994798da8cfd7fb6210ab5b
-dist/2025-02-18/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=e5cef28308348a378835ced449affa965f49d9b7382d28cbf32337ae94ebc9cd
-dist/2025-02-18/rust-std-beta-armv7a-none-eabi.tar.gz=210229d27f6d574670e9406b98748869212e66713a8ad37f2e5b67ebf27e43ab
-dist/2025-02-18/rust-std-beta-armv7a-none-eabi.tar.xz=323197f1dc3fe70e0a540df8a5f5d9475dcb390f1685bef54ba355ad3b48f316
-dist/2025-02-18/rust-std-beta-armv7r-none-eabi.tar.gz=f66d3a794ea7ea0df73b5df389738e6b3e1790b27c06187de2ed1888743ecb57
-dist/2025-02-18/rust-std-beta-armv7r-none-eabi.tar.xz=ae1465d82ea49e5ed33ac95dc0ece4c8fd0ce3df20b21a6a44ed93f33d131aca
-dist/2025-02-18/rust-std-beta-armv7r-none-eabihf.tar.gz=fa0d84655bfb7488c9c378ecf833edbde08c652d25fbc9092ed2707b320f657a
-dist/2025-02-18/rust-std-beta-armv7r-none-eabihf.tar.xz=251ba3b71c4a0bbdc327a84ee1b3c3deeeed3917fe55aadff9a52a44063f6270
-dist/2025-02-18/rust-std-beta-i586-pc-windows-msvc.tar.gz=9d9d89b206dc85323a7ee765447d1cafc2fab9189be88e1558709d94c51f2298
-dist/2025-02-18/rust-std-beta-i586-pc-windows-msvc.tar.xz=b124483bdffbb41b5c806f6bcc1003ba15d031cf5fe02eaead555abe15da20a6
-dist/2025-02-18/rust-std-beta-i586-unknown-linux-gnu.tar.gz=914925fb75c45cd9939c8692b02efd337b814040ca9bce369d812b97698a4c3e
-dist/2025-02-18/rust-std-beta-i586-unknown-linux-gnu.tar.xz=eefceae8f0d42a5e3524ac134afa9a13e938f1680edf605cca2e2d9dfbd33682
-dist/2025-02-18/rust-std-beta-i586-unknown-linux-musl.tar.gz=4baafd6924c5ab59c0c4dfd30272c08328ea1f31b70e8a9a3dababb94c1dee03
-dist/2025-02-18/rust-std-beta-i586-unknown-linux-musl.tar.xz=c75b6e4b50cd731d7f955956ce0afc02f04e2adc4268a1bec8b076eb1733ad28
-dist/2025-02-18/rust-std-beta-i686-linux-android.tar.gz=e067c5483336195763c2f1e9625644075fd93cc86180e6d24bee63aa26b22e99
-dist/2025-02-18/rust-std-beta-i686-linux-android.tar.xz=d4892feae881cc914b94b8bfd66b5e75cc4d62cbb697b8faa3f29d1d70d15f5f
-dist/2025-02-18/rust-std-beta-i686-pc-windows-gnu.tar.gz=ff6f43c40e2f8edc9ca21df771c3c28ab77bcb0e254adaa09d8c9433bd56fa97
-dist/2025-02-18/rust-std-beta-i686-pc-windows-gnu.tar.xz=8d6088d7ef7f13bbf576fe238e8a032091359a773845f35e3329b5d8273d1fcc
-dist/2025-02-18/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=cc62a0e5c529bb041455ed15f646e5c9c918f20a644ed7306ad8beb1abf07c1d
-dist/2025-02-18/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=9cdcd32f73d9839c5e6322f8b1e18e3abf825ddbbe9bb498616f0c058c5fb061
-dist/2025-02-18/rust-std-beta-i686-pc-windows-msvc.tar.gz=fecfb22d75b38e9c92c64790833c8ed8b4ea70c40d3d9c67a23277216c1246bb
-dist/2025-02-18/rust-std-beta-i686-pc-windows-msvc.tar.xz=a592d638118b0b95e8ef0e174b94c1825d0e3a3aab87d03737eb7415d1b32076
-dist/2025-02-18/rust-std-beta-i686-unknown-freebsd.tar.gz=e8546b2f4fe5746706d2b0d56fe174ee5993bd61a9fe451fd233236d7af0feee
-dist/2025-02-18/rust-std-beta-i686-unknown-freebsd.tar.xz=09efaf8f4f26ce6d466c1e20758901dc64348cdf390f4b878b4ee9542f50dbae
-dist/2025-02-18/rust-std-beta-i686-unknown-linux-gnu.tar.gz=e173f1ac1662deba8c719965d5d4c77e711cc0eac732d933b6c8ac021a44de5c
-dist/2025-02-18/rust-std-beta-i686-unknown-linux-gnu.tar.xz=600aa6b6ed1b49afdcc4978c897cd1e1f801193b804b0d1723319464c8378c88
-dist/2025-02-18/rust-std-beta-i686-unknown-linux-musl.tar.gz=38f7ee73e7067df2b98064b9f0ed00b8aa7c7eeae5955719fa0e2cf1f126ed19
-dist/2025-02-18/rust-std-beta-i686-unknown-linux-musl.tar.xz=6e639d9c45eda6b43ce0ce52e3213172df1875adfa0c13e52385b5aa9fa05da1
-dist/2025-02-18/rust-std-beta-i686-unknown-uefi.tar.gz=2ae2a44ad2610bbe3a97d176bbfd3e43efa22b5713c9591b9f3bcd7609f3a30b
-dist/2025-02-18/rust-std-beta-i686-unknown-uefi.tar.xz=d8fcf03e16ce9ada0253a2f8899ee9193083e1638d9e0da6cc76886b6ee14c91
-dist/2025-02-18/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=cb0f09f7d81b1e49a761a94396dcb4e999dbbea7d70e044785992da9a2aa38e2
-dist/2025-02-18/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=1cecfc8d91f5f3cb7bc67f49795d5e2c74638df0f7d66a3051a851522dae2860
-dist/2025-02-18/rust-std-beta-loongarch64-unknown-linux-musl.tar.gz=0369af7a8b56dac39448a22f1ad27df42c72ccdcb43cb96e7eaecf0c0d8b94e2
-dist/2025-02-18/rust-std-beta-loongarch64-unknown-linux-musl.tar.xz=a395fd16ea741c72b39db5d398a46a90cae8531be620a3468d0dc13f8a9979f0
-dist/2025-02-18/rust-std-beta-loongarch64-unknown-none.tar.gz=e2ce2c57ad140b9088052009efae96ed04ce14c258cd954ee049dfc9146242a7
-dist/2025-02-18/rust-std-beta-loongarch64-unknown-none.tar.xz=a055dd6cc47dad744fe9343d100750ea013cbe3a5bf4fcdac54e80809352a6d3
-dist/2025-02-18/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=26f8ba1c9594f7336ad530eef0076f2d30752d2edcf96d944cc962dde3d3caff
-dist/2025-02-18/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=32c80782a30c7bf300510e4fa29dad76d9a40bed2d5746c4d55b17fb261d788c
-dist/2025-02-18/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=2cd25291aa0c7610f10ab04cdf4ba4d214e0c684bed73d2ef31ae84af2da0eaf
-dist/2025-02-18/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=a7f02677a5c35388593142ef95cf56ffe1632df7fd42ff35bff89dafb34a0bdf
-dist/2025-02-18/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=64ee7c6fb36ea45490911ae5557f6a051728a05a7c88b1476489be87456be4bb
-dist/2025-02-18/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=250993b5a1915a8970d91f7a10f3f50c907cc9508d71d3b2c8e20914f90254a6
-dist/2025-02-18/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=deb267998a725fb0288432a51aeac3004d6430fce8683c91d102b6708e5b99ea
-dist/2025-02-18/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=49ba80f0a2970948699b78fc60ac09f77dda94e56931399c57c2c81fce8df9e4
-dist/2025-02-18/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=06ff5073e946ed2a5f80f9a5befd7b0c27e9a959cebf26b6cefc5762a0fcdb03
-dist/2025-02-18/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=27f12f5835f564b03f55d85121c9474b9fc93d3084c5b5d0fc63d33c8c9dcc64
-dist/2025-02-18/rust-std-beta-powerpc64le-unknown-linux-musl.tar.gz=78aff087bbef054b5a6a8d2a1649dd59f69b7f98635eb0c130c4ba87b3018850
-dist/2025-02-18/rust-std-beta-powerpc64le-unknown-linux-musl.tar.xz=e82b6bdfed001c91f8f88f6c37e31ef35f2f25cdca6fe8adfd90d024cc068e15
-dist/2025-02-18/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=8dd6fdb684882ce4087bb96ec2d982c0d808c93c053c774b49cfc705959b4309
-dist/2025-02-18/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=4d6db36241c3d8735e7c2ee84a37ae0cfbc2fc79c6fd259ca4b74e7edb68b8f0
-dist/2025-02-18/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=32e8a2eb316b2a82f80e7268a318df89f732d7cbaba779debe10664aec7d40de
-dist/2025-02-18/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=562030f1bdc1307bc0261a2e66c12a6f21fed0ed21fdb2140b1b1d55664aab00
-dist/2025-02-18/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=52e8c7ab87f5d2cbb712fb54ad8394b50a7f95961e1a7e5ffce981a962899a2c
-dist/2025-02-18/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=74f13bf5f0ff428c323c3041771b653d3ccf5a999105869378bf09a6ce6ca040
-dist/2025-02-18/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=e2b8a784b4c6826d00a69de8e1891a40619f4b17c6e54c5cbed349fedefbd8f1
-dist/2025-02-18/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=a231848519003a9ea1306a7da2139675516c0d94e5cbd8af140bb1a37515d7fa
-dist/2025-02-18/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=82d33d6527db7adaff8bec04c6edb4f3f7a1609fb5e5a91011a3b48dd47af93e
-dist/2025-02-18/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=bfe440ce80c4547afef2c6b8379bccde9f7206a5406c5a7ed5c06ab460ad8ba1
-dist/2025-02-18/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=728c559f432bf8487c345967a2ebc9e4eada676a6d56a68ec32d26ee9775857e
-dist/2025-02-18/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=51e7990ff209c27a15d40a684d634e5cad26d55913b897c2be6d92fcb849b7d8
-dist/2025-02-18/rust-std-beta-riscv64gc-unknown-linux-musl.tar.gz=ea66ba0e6af1fc7ce741c0838bc005abc04c6ad85c6831d2e05d04f30066281b
-dist/2025-02-18/rust-std-beta-riscv64gc-unknown-linux-musl.tar.xz=7429a295ccda168e41e9717647ba4639eceb81a73d66ad7ba01c9e7f1ca19c03
-dist/2025-02-18/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=01824c3ca49cfb433de4508282f0395bae8053866691869fb804a3058a403b02
-dist/2025-02-18/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=67e324c82c6a5c9fd279b9bf5ebabaecf35374c741e5728c2db3fbbb6eab1fd9
-dist/2025-02-18/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=466d4e5c1912937481fbd22d739987d663f3c771ff0efd676b34fc34e9266f87
-dist/2025-02-18/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=409c2870098222c09abcb1c89c7394633222bef2cba9756638e8cad058e3c524
-dist/2025-02-18/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=b31e3389756f78bf680982d6c6415c3712567e5050beddae10d2df52de560e61
-dist/2025-02-18/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=729b7433746947b88b8d4f488e2831bff1a92911b8c25f16a1208542e38d5834
-dist/2025-02-18/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=56caed9608e88e9ed6dec56ec3265d6464633ed57b14a455c626983defc87411
-dist/2025-02-18/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=9c9d16cac691185cf055117d6888a25f14c72cd110e3bc699c6e78b5d0dc70d8
-dist/2025-02-18/rust-std-beta-sparcv9-sun-solaris.tar.gz=6963215ffa1d2cf9650db8bc36f1eb5c97fb4d824a010c2a65f842fa00b4b4c0
-dist/2025-02-18/rust-std-beta-sparcv9-sun-solaris.tar.xz=9077823bd323a251347336f3c656c6847d5fefb90efed0cacadd510f42afbb74
-dist/2025-02-18/rust-std-beta-thumbv6m-none-eabi.tar.gz=f6d1b17e822403428a6ddf254caf78c75c2d91c208e035590779b51d45b7e081
-dist/2025-02-18/rust-std-beta-thumbv6m-none-eabi.tar.xz=1eb4e8ca0d8a52ddf754aec64b70e7a1f91d2746eef7e3c6d4580a0794cbfae3
-dist/2025-02-18/rust-std-beta-thumbv7em-none-eabi.tar.gz=7793950c2a0016ae90ee8fb70e881047a1f85c82f087fb02532009d6419ba6a8
-dist/2025-02-18/rust-std-beta-thumbv7em-none-eabi.tar.xz=14464141719b2b2c5d4a4b29685f3a2e336c2542ea33af01cfaec2ed7511baba
-dist/2025-02-18/rust-std-beta-thumbv7em-none-eabihf.tar.gz=62612b4da1872950af31bf3d9f0a595f019e6c4074874f4cdfa9166c5ff39434
-dist/2025-02-18/rust-std-beta-thumbv7em-none-eabihf.tar.xz=07ab29714f76693f69273a5567408307186b272061501a9ac83eebe944f66d31
-dist/2025-02-18/rust-std-beta-thumbv7m-none-eabi.tar.gz=b2da60ea5d746b607c505279b84aa2a8f3bac3e258ca867f6aeca958e50691c8
-dist/2025-02-18/rust-std-beta-thumbv7m-none-eabi.tar.xz=3eee9280fdd35f30ee9b4a2e5d8614ee916f36cd08629a574f6450721a1fe05b
-dist/2025-02-18/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=c5be169574de4fcd550b67d19834e064b81084e673764390b9f177631f3fb0ed
-dist/2025-02-18/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=bcd6ddf6493cbe17236a74c26da7e16a9a752fd39ab453866ae3301cff0c8375
-dist/2025-02-18/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=e52c2e8272a9ff9442ae6bafb7526cac424d15d4d6d1d8d210fe981b42da9b73
-dist/2025-02-18/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=81adef669c6f8f08b941b0befc6af30eb78b2717c3aacd52a1526d9545548c53
-dist/2025-02-18/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=1036f47867b7d29ae468a040c50da016e20a6a3a291714df4193895234591c00
-dist/2025-02-18/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=508b4f1e307d0b033eab345ab5106eb83ad8dad212f491f1ba92b9680f699bc6
-dist/2025-02-18/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=41c806851db8e59dc9ad8a756c8efde7dc14e8ef5dc4feb81be9351d267b6157
-dist/2025-02-18/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=f3bb9c783f4350e491fd683d057521f497314e85576b26808f4edc7d1d8612c6
-dist/2025-02-18/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=36a3e0675cc972fe6f4f860da47c9d4e0ac175191622c651fbb002207506b627
-dist/2025-02-18/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=c3287e3ebd4583a576f4bbdcfaa77fc21f6165b18573cbfdeb28593494ec14dc
-dist/2025-02-18/rust-std-beta-wasm32-unknown-emscripten.tar.gz=4a7128b50478a05d4fdad69715a0a7c9dcc745aab33cbc2e137cb670c6265001
-dist/2025-02-18/rust-std-beta-wasm32-unknown-emscripten.tar.xz=6e3b5981cca095c2414ad4d23f3e69a942a12c1d51dc9e055ad8409c5edbdcf9
-dist/2025-02-18/rust-std-beta-wasm32-unknown-unknown.tar.gz=3b0cbbb35daf13711e8f211da8e2ed4ade96f728be5e5ad3ca02e4d3e32b7262
-dist/2025-02-18/rust-std-beta-wasm32-unknown-unknown.tar.xz=4e50db69d0917f205a16fa3c4ee5e4012c000194ff75641ddeb49bbec9a2ec49
-dist/2025-02-18/rust-std-beta-wasm32-wasip1.tar.gz=d382d7f9787018480329518035fc4ce3247775633423e0f2940c3670cbdd4705
-dist/2025-02-18/rust-std-beta-wasm32-wasip1.tar.xz=e1d9c800db62bf606d9be9a75dd00ac7190acf3fd3592cbdeba67170ddb092aa
-dist/2025-02-18/rust-std-beta-wasm32-wasip1-threads.tar.gz=cc7cd664a483eace96710d341132de4f9cf2113f358722425ddcf84cfe821116
-dist/2025-02-18/rust-std-beta-wasm32-wasip1-threads.tar.xz=17156e3e57e304ab3ab10f8191a9952400182d2a46ebcd39d1cfde97b94c0756
-dist/2025-02-18/rust-std-beta-wasm32-wasip2.tar.gz=7ab89b39693bd1bc3f344dce6ad1c127ef38f64591c7be769d07603b2422800d
-dist/2025-02-18/rust-std-beta-wasm32-wasip2.tar.xz=2f53c60d0c0388ff644c17e341368e8b15d4c41b2827b03507d4efee100a1841
-dist/2025-02-18/rust-std-beta-wasm32v1-none.tar.gz=3277ec65149e708925ca7fc062cde92953d01569d2700d2831e6ff68768e5b30
-dist/2025-02-18/rust-std-beta-wasm32v1-none.tar.xz=24df037c2c4bcb3d593033d93b6e26aa1dc38161452220d7a73a23a696dc93bc
-dist/2025-02-18/rust-std-beta-x86_64-apple-darwin.tar.gz=3878e1506ee4642fdd1bd5e10025c9c289f8d03b7cea876d2348fabc2675b721
-dist/2025-02-18/rust-std-beta-x86_64-apple-darwin.tar.xz=46bdd522559b61848cfcbc8c55d95b190a134f2a0ac19e3c7ebfaea867f9780b
-dist/2025-02-18/rust-std-beta-x86_64-apple-ios.tar.gz=e914a0a4a2824f12764b0b91b0dd97a25416686839f35dea2aabde41c011f850
-dist/2025-02-18/rust-std-beta-x86_64-apple-ios.tar.xz=b44ac0cc8cab86ba9d000d2164786b5bdc115ace7990ead57aaba2b0e02750aa
-dist/2025-02-18/rust-std-beta-x86_64-apple-ios-macabi.tar.gz=497c75ec8b5f99a625d898b406d437b8902b8ad42ee1d629a0efd27cfee96e44
-dist/2025-02-18/rust-std-beta-x86_64-apple-ios-macabi.tar.xz=a53ed7bfd16d62a7f51509d32fb6cc6b1f3af331f4c4867cbc1eb57da5c3d521
-dist/2025-02-18/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=3cec5b6714f156e43c85b4b15377475bc38f65325f61de020bddfc2708b25a7b
-dist/2025-02-18/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=ea2cc73a03644647dec905100154a3238dd819fd0421f770dbc433cd6dc49f33
-dist/2025-02-18/rust-std-beta-x86_64-linux-android.tar.gz=2eaebfe572503b69e34674ed414357c514bcfbf013e6a2a7bb3fb14f501872e8
-dist/2025-02-18/rust-std-beta-x86_64-linux-android.tar.xz=66c4f03b907515831f9a48c8f5036d4c3115e814507a27abe1e423ef4a7e7c0b
-dist/2025-02-18/rust-std-beta-x86_64-pc-solaris.tar.gz=4c8f54f1709908a9edabd9e60d8492cda771db4b51fe766f2a2323a10f184e1e
-dist/2025-02-18/rust-std-beta-x86_64-pc-solaris.tar.xz=60d74169e80b3e1297b010501fa5a46a29a7541c84ceeff304b4c2ace7631540
-dist/2025-02-18/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=9d043fbcd7e180052b903180114d50c71a2ccbeb22fff7020514b4b0a11a8123
-dist/2025-02-18/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=f08905c0b8192f23f214465d757d93e30aee0250dda279d648e948961e0745ca
-dist/2025-02-18/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=e35a42a9a6eccc4b738b389fdff24ba01ef23ff8d00fbd34100acafffb9c3763
-dist/2025-02-18/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=a1fd2d1b1bb1fe9593df7835b5fb81e5c9453c0bbbc17b9ee5deb0512ad12550
-dist/2025-02-18/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=feada263ce77cd0ec635ae78c8ce34099385a1f89d1eb680576a85a8adf0d75e
-dist/2025-02-18/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=ee8def01984eba376773f7a055a18a4096750d26f96ab9150326dc60ece9fbe5
-dist/2025-02-18/rust-std-beta-x86_64-unknown-freebsd.tar.gz=7791a0155a0a3464d07b176383a4b61dcfaef4bf0247c58d447402fac3123186
-dist/2025-02-18/rust-std-beta-x86_64-unknown-freebsd.tar.xz=11bae401884cce0306b415bb1202c2c63f81395677057fbbe12e9302951a9d3d
-dist/2025-02-18/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=4d05cd943f4e4250d50a5f732a64f32431a6cfef59b38bc087b1dbe1aa4b9561
-dist/2025-02-18/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=7bdc7161d66b6c330f027f53b15f164c9ad4d55debe77b7c34971a877bf82caa
-dist/2025-02-18/rust-std-beta-x86_64-unknown-illumos.tar.gz=01edf8fdab00df25cfea2ade367dc4f66a1d08d11bfd9a7e56b65a723e14b517
-dist/2025-02-18/rust-std-beta-x86_64-unknown-illumos.tar.xz=9efccf8ba6fc68997123924cddd7008b15f1a57170d03597a370346fdc6c83d6
-dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=9dbfabe77853e672d576e70332e07727882cd6af14dee9a00d5186b43763ce82
-dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=04e31482a3ff18d8fdff40c4e95b22bc667bc0dd1ba06fadbe2479bae5d97288
-dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=ebb6e0c56d905ef064fa15449a72746daa9e3998f5aba5c6a3c132bc676228cd
-dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=818fc179c8380f0fb70c46e04086926a69b026591ab62cfbc1051abc5c80012a
-dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=c0a1c692a334821d61a9b92cd1332f047175d4335336db3e2129687ba96ce5bc
-dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=2c71b87db4cec49e3c620e6b4e0e07f1aaaffe69020b07c87546232ed1ad3b20
-dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=c1bbf445dd0b187904af5871bf48a720151ef75fdd3dd13161dad01ef5e87bbc
-dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=19963165ec2c35c15024869c16a707bdc90e72032ebf6e203cc67411ec8ba7c7
-dist/2025-02-18/rust-std-beta-x86_64-unknown-netbsd.tar.gz=63fbbd51047125fe30f1954ea19a05d6f051d2a77929952bab326c8ded6db8d3
-dist/2025-02-18/rust-std-beta-x86_64-unknown-netbsd.tar.xz=1c255d1de9c2629210575b862600bf369499a0eb8873178ceff4a337ba9dccfe
-dist/2025-02-18/rust-std-beta-x86_64-unknown-none.tar.gz=781f14a54c5e68acde1e68042905a48f687294e2bc61450f422a6e15bf6ab509
-dist/2025-02-18/rust-std-beta-x86_64-unknown-none.tar.xz=d45921b98740f3cce5833bc4fb1e36816f34b81e96c3ca2c76deff4744134c6c
-dist/2025-02-18/rust-std-beta-x86_64-unknown-redox.tar.gz=0cd76d3c5b051b0b2015cb08079ea3b5ecbb9b0b68779eb35946721b24c07008
-dist/2025-02-18/rust-std-beta-x86_64-unknown-redox.tar.xz=6dec719cdb7f35f6eafd901414525b40f030566bdf3fb55e3b05de162dbf0741
-dist/2025-02-18/rust-std-beta-x86_64-unknown-uefi.tar.gz=aad1e2cfd4f428acb67d9dac1fab4450eccfe9212f52f99f06c09899285b6b1e
-dist/2025-02-18/rust-std-beta-x86_64-unknown-uefi.tar.xz=4252b618ffc906949756ad28a5437d11b0353fe1d755ee1d23502a208bdee74c
-dist/2025-02-18/cargo-beta-aarch64-apple-darwin.tar.gz=2f7f459d2595d3f60bcef4ccbd3c72095a3ec54fa3f2221a647ae892c308d5b2
-dist/2025-02-18/cargo-beta-aarch64-apple-darwin.tar.xz=501feb9138f3c11a13fd649d6573924ead10f5e6fb1e759d880684bff11c12be
-dist/2025-02-18/cargo-beta-aarch64-pc-windows-msvc.tar.gz=b589177b0287a42ce17939dbbee92d883dfec88ebad33bf9a719a3cb2f446533
-dist/2025-02-18/cargo-beta-aarch64-pc-windows-msvc.tar.xz=d795082d304ecdde233a4b6bb3aa558392b2c5a1553fab213ee99648c49f7a51
-dist/2025-02-18/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=8444d938514ad2d55769cf614774dfb4e5a27c34f8ba8b49329a2bcf0b000162
-dist/2025-02-18/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=02e52fc13ae52066031ac40dad039ad752b83582e5f9e74ecef206aa9206ac16
-dist/2025-02-18/cargo-beta-aarch64-unknown-linux-musl.tar.gz=e89709bb552e7ee73de02b08c6d8820b07bccdc09777eff9716efabb2bdd50cd
-dist/2025-02-18/cargo-beta-aarch64-unknown-linux-musl.tar.xz=50944f0e51190f9db065764afc7a41a3a1e39767bd1ef5ec659c98fe9243cc98
-dist/2025-02-18/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=0343dfc2f015d476b3aca59b33dd75f907f595bc24715e6c518194ab1a5dfec1
-dist/2025-02-18/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=3dd6c378c10172b1abfdd1db2fa764d1b48153ac1b5065cf124399941d036e56
-dist/2025-02-18/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=6eac5ffb9adaf2591d3b1872249f4a959c04afdf6694e62dc850936aa8d35972
-dist/2025-02-18/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=484510e6b9519c2b047864584253c8c1f725ce843e8dd3117349032314737462
-dist/2025-02-18/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=fcf4d4b2d401ea689ee32f38b4a61c77b52ff4d3d114b23d0262bd02c3d1ab5d
-dist/2025-02-18/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=1a75296c42d6cf93a5e51ecb2b2bfbf0cdea350668d610e8b0c90937163b4f33
-dist/2025-02-18/cargo-beta-i686-pc-windows-gnu.tar.gz=d1b5147ec79466ab9441825b4761e89cebe57ad21a3199b0eca0779683c45ed6
-dist/2025-02-18/cargo-beta-i686-pc-windows-gnu.tar.xz=980850e06ccd90512baebbfe3baaa65b5c089edbae8146fd940c708fd7556abc
-dist/2025-02-18/cargo-beta-i686-pc-windows-msvc.tar.gz=78c67ba481cc7b855b54a2edc0297bfb5eadcd83d5a028b05291415417bc6947
-dist/2025-02-18/cargo-beta-i686-pc-windows-msvc.tar.xz=6ea74c750e6e0a794965c6616e5b1a82dee295815b0c24a3898952b1a5a02c8a
-dist/2025-02-18/cargo-beta-i686-unknown-linux-gnu.tar.gz=a0c8f67fe77b94674698b4816c081e2ef08500990c0f9eb069d0190df9c4f129
-dist/2025-02-18/cargo-beta-i686-unknown-linux-gnu.tar.xz=9b13f958ec4edff194858e90c54866a129e88769a76fe22582b07e17540708c3
-dist/2025-02-18/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=f4d2f1c8a7bec6d2b8378aa87a324c42f0f414962174b40b6f0d1dc21d0cacf4
-dist/2025-02-18/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=f25659ef3be1a28da8821eb178e02108f41cd5c0b87aa01a052a3a90e7a9da50
-dist/2025-02-18/cargo-beta-loongarch64-unknown-linux-musl.tar.gz=b687a7c3fac08680818804e034af6689f1bbcf8fc0e406c99b2a49ddae1e900d
-dist/2025-02-18/cargo-beta-loongarch64-unknown-linux-musl.tar.xz=e33818d2f94e8ba148dbf8cd53d6396e370157acba6d0865a5ac71d292939a0a
-dist/2025-02-18/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=9cdc2115bd2022cb0b0ac4f1c71142c064957137decc028dde7585acabb8b780
-dist/2025-02-18/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=f722447494f0a7af9c31b71364aa4a2fde79a9887440d8281e4561f7d71620d3
-dist/2025-02-18/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=d8a30f9e48e89cb1d18532fd7fbef8eeceef6bc602ffaf9e730c635e2fdbb156
-dist/2025-02-18/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=ec6b3b1595c5761b8092a04a412e79534c28910ed78ed792c9af7ddc4d92a389
-dist/2025-02-18/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=4bf9c73173199fd3ca952d33702288deb483c7fd392179352135b64e7e8fadb4
-dist/2025-02-18/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=12aa06644e07344a77d0c16dc1ed96bfba63de02df1f432d57b82f8a1e2282b6
-dist/2025-02-18/cargo-beta-powerpc64le-unknown-linux-musl.tar.gz=eab362146d449dcdd10740c8e6f9dec6e640ffcca162eb51febbc835e34acdfd
-dist/2025-02-18/cargo-beta-powerpc64le-unknown-linux-musl.tar.xz=867b716eae9225c66c0ab4642e4e497055ad2effd24343bdf80354ce2845d6f9
-dist/2025-02-18/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=0503ba2e4b1d668fa3a3174f96ec3fcc12ff767574a7af8ef5fc824ca86dc965
-dist/2025-02-18/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=478b9f1d4f517f93f15530d27a7d55ea29cdd06eccf01176ffd08c0ee3204c1f
-dist/2025-02-18/cargo-beta-s390x-unknown-linux-gnu.tar.gz=419a679aaf6e164649538916daf28081a063bd56c7b86ff0e2df58072f334fdc
-dist/2025-02-18/cargo-beta-s390x-unknown-linux-gnu.tar.xz=31b39e242035036c1101412b7c86387e1183063ff5f6ce67d311d0764435a588
-dist/2025-02-18/cargo-beta-x86_64-apple-darwin.tar.gz=d6d5224228dd54b6d16be30271111620c02fd88e656b8bbd22452b66b0d5cb56
-dist/2025-02-18/cargo-beta-x86_64-apple-darwin.tar.xz=cbeff7c031b4ab4732207b90ee8849b27f03cb28d3e085bf4d70444347dbfc99
-dist/2025-02-18/cargo-beta-x86_64-pc-windows-gnu.tar.gz=ae5922955ec579732aacd8112bc53bf5333438eb81d0f81dc5f387888ac979a3
-dist/2025-02-18/cargo-beta-x86_64-pc-windows-gnu.tar.xz=553c55a2bc8eae2c8ba831823a97f2232808af1f753642ec4cdd09c33dd3f6ae
-dist/2025-02-18/cargo-beta-x86_64-pc-windows-msvc.tar.gz=d9b2cf14565478429fba6266f0c86a58f3bbd1ce11a63268828b33ccb55759cf
-dist/2025-02-18/cargo-beta-x86_64-pc-windows-msvc.tar.xz=2e8c0560355d11a038219072d2503860f5c5b3cd137b89ad931f54d9bba60499
-dist/2025-02-18/cargo-beta-x86_64-unknown-freebsd.tar.gz=4b528361607845e6f8ece403bbdb8d77c6159ec137396319562ea2772502792f
-dist/2025-02-18/cargo-beta-x86_64-unknown-freebsd.tar.xz=c244ec4f97420c29c690e32bd6d8f14994bf1d990747f31a3dc0f2b37644493e
-dist/2025-02-18/cargo-beta-x86_64-unknown-illumos.tar.gz=7d3b49df93e87322a9e99e36c6df020d3311c5538ad2298d8b5d8f2d9ad3e0d3
-dist/2025-02-18/cargo-beta-x86_64-unknown-illumos.tar.xz=136ce90487448ee770472d4bd2c0d9c96200f0ec762419feb42fefa26ba36b58
-dist/2025-02-18/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=510538965ea142405925d3f4f03a87783516407989b8aa7be07fb84c0680e9fa
-dist/2025-02-18/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=a8c569398d71cab0b90c809b1d869a2e3c5037407b5af804df08c205775981c2
-dist/2025-02-18/cargo-beta-x86_64-unknown-linux-musl.tar.gz=1493f66e5cb12e8b955841804e7df745e26daea2278144aa57670192c4c62cef
-dist/2025-02-18/cargo-beta-x86_64-unknown-linux-musl.tar.xz=472bbe49415557b75b572879d0c33750731c1fe9e56cc6ef3b0fd5532e56446c
-dist/2025-02-18/cargo-beta-x86_64-unknown-netbsd.tar.gz=d3baa6019e13449c01fbeebebce42027ce4ba70841cf28733f6849e7c6ce5d89
-dist/2025-02-18/cargo-beta-x86_64-unknown-netbsd.tar.xz=0db9af42e9ad914a99db4924721c895cdf490bc5351bc8c2d8993e3569e952e4
-dist/2025-02-18/clippy-beta-aarch64-apple-darwin.tar.gz=6ce3b464744082131c99a213454225e5702564c83032e11dd0f3d95530a4e0af
-dist/2025-02-18/clippy-beta-aarch64-apple-darwin.tar.xz=925baff0d91b959a99c989a4ada70973baf3da03e1d7e7e8be1fa334c3acbc50
-dist/2025-02-18/clippy-beta-aarch64-pc-windows-msvc.tar.gz=76d265c2fb6280eb8ed399501964f301a50e09e548cee708ebacc978d8db538c
-dist/2025-02-18/clippy-beta-aarch64-pc-windows-msvc.tar.xz=e3d1d69cbc838ab639b2e41537b10266f1b6998a228882d4041f35cbb8984909
-dist/2025-02-18/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=918191cad727d795b51f892abb6e4fc87ed735bfcb51433cfb4371cb8be8690c
-dist/2025-02-18/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=157d6eb9e7dd80dda7daae5584d095a5e68d13ba8b1d1229e90b5b51f6670e8d
-dist/2025-02-18/clippy-beta-aarch64-unknown-linux-musl.tar.gz=fd4de290450e3d3c9188263d9506167e298f4c2d4c781fb3573806694b5ca1ba
-dist/2025-02-18/clippy-beta-aarch64-unknown-linux-musl.tar.xz=335c5fd24d1c118e4d1d8abc43d3529dafc9b30af39f6b009924cd0fea676182
-dist/2025-02-18/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=209cdd2042e293d1061b149d97333515821dda0ffeb9b30f24dd2dbb4c1ad548
-dist/2025-02-18/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=57dbfdc34ff4e74aaa8776b80d35aaf0317fdc314ee4b0f3bf58fc672963cf38
-dist/2025-02-18/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=a89a2562fe9ac6492a5de220c395f433b0e53a8b29c72b3a8d4843f996649ca6
-dist/2025-02-18/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=0e6ff6453df1397e7b12e7e356e7c7300cfb1f85bc3a6705735067128d2a8135
-dist/2025-02-18/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=7764c2dbaf217f4b1d8ca4ed2ceaacbb91e8010d26ae1bb10b808afd5dc6a798
-dist/2025-02-18/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=b7a042eb6830653a623c6299ef57492ae6c9b51a9cd8480f0a6fc2fb6d378bbb
-dist/2025-02-18/clippy-beta-i686-pc-windows-gnu.tar.gz=ff41e5b666b3531ccdc0ee836dceb270179d6a849e47024eedc6ea309d36791a
-dist/2025-02-18/clippy-beta-i686-pc-windows-gnu.tar.xz=98c6386b63ed89dd96beea223f4c720320b6ca460f11b77c46427e128034cbbb
-dist/2025-02-18/clippy-beta-i686-pc-windows-msvc.tar.gz=12bd371402e4d3251f60fa29b3b3aca88b4480229088b68791dffbb4ae1554ce
-dist/2025-02-18/clippy-beta-i686-pc-windows-msvc.tar.xz=62a22d1e9b4fdba254e549f5edb276bef5252754ba67a76526d5aeca85515646
-dist/2025-02-18/clippy-beta-i686-unknown-linux-gnu.tar.gz=04179b3a20a68ae2fd8444832ea4edd8155dc9296c7a1edf101053e3ff934891
-dist/2025-02-18/clippy-beta-i686-unknown-linux-gnu.tar.xz=c955e464e99097025fc7d0e42bf90342f74f475c5148526df2f51ca46ce8db4d
-dist/2025-02-18/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=6f58d326a1f2a35246384640b999f95a961a9fe1e5a3c4a3e67d7f96e1ef43fb
-dist/2025-02-18/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=583b1d55a38fdd473a3f3f3cc0fbeac808fbeb593b8b45c7a6b8a09dec0d68cf
-dist/2025-02-18/clippy-beta-loongarch64-unknown-linux-musl.tar.gz=80d73fe94ecbbcdb14b35e1616d52e0bb9b1f04dcdd4fc384e7103cc36325014
-dist/2025-02-18/clippy-beta-loongarch64-unknown-linux-musl.tar.xz=1bae908e4d3931eb4dc71ac1524f990bbccaadd9d30897bf516899baebd4c5d5
-dist/2025-02-18/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=b882e7ea97e0d36b289a46ef84b14b2b44ccea93ebdc77b2ab3430361ad15b1f
-dist/2025-02-18/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=91e52dc398dccbafd040e401f155c204f2a14d5f62aecfc24912910d5e45008d
-dist/2025-02-18/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=c81497f2b2d2670b9dea2e35804e10780c1631a8761d4bc3331767c1ccaad6b9
-dist/2025-02-18/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=6236e129f3e551a3126fa07662cc8ad512ad5fcf436a8da9e27a915ad4c234cf
-dist/2025-02-18/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=1b031f055ea4ab4a9da0c8bfb0037e92b493caf7879351f8b404a96c447ec92c
-dist/2025-02-18/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=2f07224e49f7cab10d673116d9dee9f964b4c44ac3db336e7ddbab9e0b1bc698
-dist/2025-02-18/clippy-beta-powerpc64le-unknown-linux-musl.tar.gz=84a8295a7066d258404c87d2269a01d89cc7efd0f143ab53689597f3fb351417
-dist/2025-02-18/clippy-beta-powerpc64le-unknown-linux-musl.tar.xz=019460a6b0e1c5c1331d5a54f3e45306ba0d1b1c2206e2e69f38c1c3501cf741
-dist/2025-02-18/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=aba8f7bd0a89205961f9803418cdf9bb63a7d72bab4a1ff937f4a142921f4833
-dist/2025-02-18/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=4607503ba131ca655dab86ad48c1737f216f8ec25ba6dfddbf1f0807e5a6dd2a
-dist/2025-02-18/clippy-beta-s390x-unknown-linux-gnu.tar.gz=b0170f9b9e13d4f6e016124fd40c858e00155479fb4f96c1edc896130bb76dcd
-dist/2025-02-18/clippy-beta-s390x-unknown-linux-gnu.tar.xz=397f0a8944beffb87c74717bd0f422836b3daccfa848d91c0a65875031bf12fa
-dist/2025-02-18/clippy-beta-x86_64-apple-darwin.tar.gz=11be90b9b09f4e24e56df2a602ed8161023314514121d9f76e424fb628df468c
-dist/2025-02-18/clippy-beta-x86_64-apple-darwin.tar.xz=16d313798f12d0e74f888b627e079606958de58eb2ca4c70d5f7de8cce72620c
-dist/2025-02-18/clippy-beta-x86_64-pc-windows-gnu.tar.gz=41ed081e4a7b205cde3fe958db18ffe1c1ac5a9c336f965a03fe89499a3eddbd
-dist/2025-02-18/clippy-beta-x86_64-pc-windows-gnu.tar.xz=daaa3267dcbb3daa0cae47861683f29da5b7419214ec5949e242aa93e3f87148
-dist/2025-02-18/clippy-beta-x86_64-pc-windows-msvc.tar.gz=6d9b8f549e34d8fb65987b39c01c27fbb0e18e8950a07ec6fd1888d01e253971
-dist/2025-02-18/clippy-beta-x86_64-pc-windows-msvc.tar.xz=1c26b51c484f5b10ee693212e258fb86c63a2b59e631542918799d480a3587d4
-dist/2025-02-18/clippy-beta-x86_64-unknown-freebsd.tar.gz=a42777c542773a4262ac9fcb07ed13f769957f58a795160441241ad4e4f5258a
-dist/2025-02-18/clippy-beta-x86_64-unknown-freebsd.tar.xz=9e809fa141ac68557f203aec2a6cc02a4ddd22169595c40ed4a964801ccadb1d
-dist/2025-02-18/clippy-beta-x86_64-unknown-illumos.tar.gz=4e65b5db249a18e73247029506f619393be7042f2c91a00301962effb76a18ea
-dist/2025-02-18/clippy-beta-x86_64-unknown-illumos.tar.xz=6714018d069fbce271c177f1941a6b77f18b67af462596aff273f7db1970ef4a
-dist/2025-02-18/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=72a8ee3bad3d638af0cc3ba6c0c0ed1594abe609573de71d9c7a884a8ac7645c
-dist/2025-02-18/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=f622befd60c3695d3d62642b953deabc3e3f04b32cae8a7cc228cb534244adbc
-dist/2025-02-18/clippy-beta-x86_64-unknown-linux-musl.tar.gz=8946e02ab98281b6949c4d725a5fe3fb1bfc86651a675e451f126fec8d053762
-dist/2025-02-18/clippy-beta-x86_64-unknown-linux-musl.tar.xz=425907bd4320c516647e5dd6df6154746d64854fe2e78f27283b7fcb27164de7
-dist/2025-02-18/clippy-beta-x86_64-unknown-netbsd.tar.gz=505208d2d73ed7278e5b29d8450c382a89e4c0992d6199243e07c8640c611b85
-dist/2025-02-18/clippy-beta-x86_64-unknown-netbsd.tar.xz=d4b0306e7d7db5cb7da977a7ca72fff2070f102ac385c3b35286da25033582af
-dist/2025-02-18/rustfmt-nightly-aarch64-apple-darwin.tar.gz=13854358645915af29d9337bb87301aa1a5e76ecc86a934dd640d02af3255ea2
-dist/2025-02-18/rustfmt-nightly-aarch64-apple-darwin.tar.xz=0cd190bd5a064235f9cd6f6e7eae4725b3b53ae36493b3ea54b8f190372ba3ee
-dist/2025-02-18/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=20b3f8c4c7b02158181970804d419b16f85a1083943e1c384e0bcef441f32aff
-dist/2025-02-18/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=1ace0f10060d2fc35a1f05a1d61adebf95212e8b46a2234c2e78030481c1b3e9
-dist/2025-02-18/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=e5ad64d67931df49f6b7d3448e9860699d6549c2b4a96abda1a03069b45f339b
-dist/2025-02-18/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=e8112ae80c8fd43452612b79dabf471be561b7e828c9a2141c698429d761a49b
-dist/2025-02-18/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=8ad36bbe888e61b6d7e540ba4a2478652f14c1b28dbbcaab732003293b7c985b
-dist/2025-02-18/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=1794af320a273f4a951942ff0cd73a359fd82a971c572af1ab7ff2961340791c
-dist/2025-02-18/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=67b9d1d3c46bcce0aa94d6cb4155cdf7376677caf2e19685553266f781eb7cc1
-dist/2025-02-18/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=9d7b97a85b1368cfc78f1df42afb08aa04eb17fbb91ceb3c379d59fab4294890
-dist/2025-02-18/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=42396c7bd206d0fa07f3b44fcb894ac074e2af07eb158c1ef630bb5467151c8f
-dist/2025-02-18/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=6881c9681342f1430fd9cc8c9786cee40522be3dcd0fc4dcf2b3957d9d53f03e
-dist/2025-02-18/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=6cb8973ac4215d67aad9bb56521024626d7883a6e00748623a728dd9107698db
-dist/2025-02-18/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=920d877e04260be6ccf9963bea12220e886df673cbc48b55925650f8f5b21d9f
-dist/2025-02-18/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=ec5c7105f2c2a2055f704435fff9edbbee0a234e63050676c034f983d4e341ee
-dist/2025-02-18/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=ab408b64db4bd47abf8e24c0f611f2c67a3c9ce7e2138a92772e0510c6dce5f9
-dist/2025-02-18/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=d04250bc2e57fcb03f1d80722f2ac1117f797d768262d7630c9b53af808a8c9d
-dist/2025-02-18/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=6d7be9f04a46040f068544e32eb84c98afc1f81b750beb229def84a7513150fb
-dist/2025-02-18/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=94f585a7c666dc9c95c3ae14744e614a3fbe37b3e31b476b48bc4ef3289bdd46
-dist/2025-02-18/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=83e82932245b3c1d3c275126184f942b9cb8bf20f0d40c7cb1efb6f918327b9d
-dist/2025-02-18/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=9c8cb5a14294c48f8ee972d5f460751a8bae5b541bff3d872c85812b621c39d8
-dist/2025-02-18/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=4f616740bef30599e6950ae2d8ae694513003e14122f6002a9d60bdc64f77cfc
-dist/2025-02-18/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=a668e7be7946f6a9099486a40256f17832288322c9237d931f172ed76caf678d
-dist/2025-02-18/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=b02c57c217f358ff4344ee2afcbb8353cffc0a012f970d9520ad233d188d59e2
-dist/2025-02-18/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=9baf04e268999020372b21484ecc4f5aa001b3bcee05619ae5b0a11571a3a45f
-dist/2025-02-18/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=b2c2c3a0eecca7b4c35eabf09e215158c48eb426899e365db1c91c1c560ad255
-dist/2025-02-18/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=c42df8e575a24a5edbc58b5b46a89a226188d2aafc59da89d568acbb6e9cceb6
-dist/2025-02-18/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=fee7c373bb8fee5c7d4e43d7a7046d3bb156d3e496ed21cddf20c21ffdef3e69
-dist/2025-02-18/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=a0ae21a3b56e20e667c72d92ad4bacd4abb77d1fea32949d7dd62a56d6b531d3
-dist/2025-02-18/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=fc7e21cbd61169b37e81c73d4d5353d7e54ca322fd01491d9f37ff3666557e7e
-dist/2025-02-18/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.gz=e08ceaa9241c2e53041b107af09674ca4fbc4e12b1371254869e3d80d5c907ab
-dist/2025-02-18/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.xz=9f208dc6e5938a128174263349345e9fe7f587689f6a53fe5d026ae3c6fbed2c
-dist/2025-02-18/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=44abe49dfc0492cb3ab28f0aae0d784c982063399a38f8f13016f3dde123948a
-dist/2025-02-18/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=72fa294f92ab244608c384d6ad6eea0e540e6fc58181fd65a4fce0c5029c39fd
-dist/2025-02-18/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=556dcf393856c6d9c9c6731b02e34146f9f956f588025b6a614b8802032d125a
-dist/2025-02-18/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=93906364910891f71e13e0ecb07f02b707e42e11a0f1b117c590804dfa16a9d1
-dist/2025-02-18/rustfmt-nightly-x86_64-apple-darwin.tar.gz=7022c760f457075fb353e59984dcb551600581a315fd17ea1320b892b1d99a55
-dist/2025-02-18/rustfmt-nightly-x86_64-apple-darwin.tar.xz=e085ee261acbaa41361a0263dd8f13644f8a4e3679eca6bb0851b03c647b80e8
-dist/2025-02-18/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=2436e18fefae02554e620a1131455d923c1b67e00e878c75a941a6eedb4eae28
-dist/2025-02-18/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=9f6e37b5973925d07115e517e6a3e490a221218f48fd101a20670da2c3d01add
-dist/2025-02-18/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=78f492a26981e7a6f9f3e8bbd1e880682e55cede081f3cfb13a2ec5f736edbb2
-dist/2025-02-18/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=d4d788fa3e3b9a598aa7baec47af3b56362224533be85dd68a411f35f8800b2d
-dist/2025-02-18/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=8922186dedf0b12e9aa2bb041b76be8fccd43b9322c3496c688355f34bbd7a59
-dist/2025-02-18/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=6325e43f2c28118a9525f5c5fc09de9fb9a09ffb4aaad31f28d394c233ee8398
-dist/2025-02-18/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=7f317107f8319c650973cef52f745c2a8e57ea6a087910b6979404f2cb2f1cff
-dist/2025-02-18/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=b273be4897e83f786020bce1dc5dd1caf01e2ea43f085391c0031277718feba0
-dist/2025-02-18/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=0373011266a9ab62f45fa137a4bfdb970ccad8bbbb74bf776466d203f28d226b
-dist/2025-02-18/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=62748525678370dbda7f1cbd12a384e95d4af76103de998785278f6d1f076177
-dist/2025-02-18/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=30eeb980720d8c22bc45c012c4fd212e118195206b8b993630f074e526e6693a
-dist/2025-02-18/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=2f3843d9544fa56dc87f1d13ef79c68c1e68d84bec007f0345159a7448368dfe
-dist/2025-02-18/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=a86eaeab8f5f45d16eaf355a46d8b19afcd8c46db732432091156e381aa79cb6
-dist/2025-02-18/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=144cd28da601c331f6501c634ad89286be213a69cf521435e35657c5f6fe2afd
-dist/2025-02-18/rustc-nightly-aarch64-apple-darwin.tar.gz=21101db859a550ab39de1ecdec75f4f058934ed8e0ab7dfadbb2efab57bc5e0a
-dist/2025-02-18/rustc-nightly-aarch64-apple-darwin.tar.xz=a40da26e908810701112b9d3f9ab83515c8e2f4b33219f8f773c5459366d37e1
-dist/2025-02-18/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=5391bc993b7208c10a6f4256417c9f76a4a33d167b2fd547b57af614d3fc8458
-dist/2025-02-18/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=d72a205f52173b1726d8341a9436e62439b1987fe0cd4d2bbff740e38f629b41
-dist/2025-02-18/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=185e052bf2ba1cda4b6ad1c49a9f65b906899ad1ca09cd864d6041941ad344dc
-dist/2025-02-18/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=640f7af3fef5f0abacdaa292ce17255433ee16f12bfc2d2e81d70afcf9fcdd8f
-dist/2025-02-18/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=8cdee468a90606b21a8cc3305f2b6b3eb7e3d687263f4ca8319c709cda2a324f
-dist/2025-02-18/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=358bbfb24816c781e07d5480a5606dce27068f856c0a606873ceba05c9540c3c
-dist/2025-02-18/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=b220757cc8ed39c429c49b55e293ded3e07239d2e2bab8a9054ce55581393c47
-dist/2025-02-18/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=18d3cbc49e44b7810b498517d21390e39bee7ca8351c8b321592e83301ad79e9
-dist/2025-02-18/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=77ac127bae48859f57d9bd8337ac4a0bda95b1190e451abeaf7e77f1a240a647
-dist/2025-02-18/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=79009bbf0325f9db0c905d74cb0f139c92478a0b2fb5edaf383366b0e654a172
-dist/2025-02-18/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=8264c7ed7bc47953ae76cf87236655562a55846abb195bc9281833a0da168db6
-dist/2025-02-18/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=c6a85e7f2a469fb05f0a84ceaea25dc0d95b57bd4d68dcee447918162cb36b2a
-dist/2025-02-18/rustc-nightly-i686-pc-windows-gnu.tar.gz=0f31c9ed4ba7e942806fc2927d305f9d3ad676cf81e53e0f7c4123aef375fedc
-dist/2025-02-18/rustc-nightly-i686-pc-windows-gnu.tar.xz=350f4b46dee2aa6ebfc31912cfae5c7c1db99b298c52834308e95c504cadbe7d
-dist/2025-02-18/rustc-nightly-i686-pc-windows-msvc.tar.gz=e12a40b7178995ac223eb7fa317e1114a988256d99fe615f70d64cf3f2891fa7
-dist/2025-02-18/rustc-nightly-i686-pc-windows-msvc.tar.xz=09fb4a4744a55bf8fd6371e5496f6a9c00b119ddf20b19855653d66d9a618214
-dist/2025-02-18/rustc-nightly-i686-unknown-linux-gnu.tar.gz=52361a34730f8bf14eefad7e51f66fc3ba3be405a364d4520103208fe8fdc056
-dist/2025-02-18/rustc-nightly-i686-unknown-linux-gnu.tar.xz=ea81964fc8bcb8b43968acb6a4f7fdec2ddea9f75a8be5446fb01b4267d0d75f
-dist/2025-02-18/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=11e7a143112b6abf818652e425b6f092464cc9d8f5286e90180c7af8d5939643
-dist/2025-02-18/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=86f5d40eecccb623ff744bbc1fb40458949db9b2f8501cadc6be9bca95f6c693
-dist/2025-02-18/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=1be7ecdf609958fb0ef945203b22a600f1e343ee7fc581f6451eecd39f1e0b7e
-dist/2025-02-18/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=03d3b67092da64f7b7be7ba4e115cfad4071c0bea3abb5e60ac166127713b169
-dist/2025-02-18/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=4e33311490c2dcf79a16307e1141ce37574ec3829a1e93d0f5b06ff68ad5c861
-dist/2025-02-18/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=504c102fa1c8dc5042cb354a60b87c0f6d47f9adab341f496af723f3ea8bd548
-dist/2025-02-18/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=c559971ae42a5e0e999e2fe119033bffbfe8c64b767e697e0b95f5dfc271d13e
-dist/2025-02-18/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=51159ab0ade5a62e128b6c794da5c9815324470c468e5808b50663c3a0df6d39
-dist/2025-02-18/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=a8134f8f7ea4531d54ab5c0a0894f140ce5182a384c57395edbe06ed551970ab
-dist/2025-02-18/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=8f2f5d88ba9f4ee946db5f00d56c4852213dcb0b46ce2793966af6c96d934dc6
-dist/2025-02-18/rustc-nightly-powerpc64le-unknown-linux-musl.tar.gz=7bfc6666757b57fa6160d076a9eb52852dcb5bf788bd12c0f014bbd552b8a7ef
-dist/2025-02-18/rustc-nightly-powerpc64le-unknown-linux-musl.tar.xz=e2c3293e2a90012ad48bbc2b6f285adf20f356ff1f4146b3f11543511bbb3c44
-dist/2025-02-18/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=f582a59b5a6cbe6d58400c69f1cad4f34d0f1541c1ffb9df3ce71846edd828fe
-dist/2025-02-18/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=244384bd94f7c3606a086abc8be9d36a855faf09d9bb6b121f42e168c526e717
-dist/2025-02-18/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=327e29662140cb76b1ff362fe51f9a12fb4ec304929317ed8de7295fdb9c5b9f
-dist/2025-02-18/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=a2c4e19b3a8dabd5c8fe72edd60d1925947cad5971c77c62f12fca764c6e4e7a
-dist/2025-02-18/rustc-nightly-x86_64-apple-darwin.tar.gz=b6812f92e08cff1b706380637fdd553b04b9cea746ffb69e6488fbec70680136
-dist/2025-02-18/rustc-nightly-x86_64-apple-darwin.tar.xz=f2502b2a810938c41e2302a9112c97d04998ada16583373e6488bcca00595761
-dist/2025-02-18/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=9159f7323718c6a8b98f7de5186ed507b3dca1bfcce9bdfa6437313bd630a989
-dist/2025-02-18/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=10d54c9b80570b6729d0e68f017d862c5126f09b42f150d004aa8fd5382b165c
-dist/2025-02-18/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=1f29c1aef1dcc3ff9f2e3013b7ea0521829e6e474f9058cb70fea65180230b41
-dist/2025-02-18/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=18cddaf7653f146dcc8a44ca0cc33c6dd3c24f28fff87aedca01fe3beaaa9915
-dist/2025-02-18/rustc-nightly-x86_64-unknown-freebsd.tar.gz=e57c1477cf9b75e727db48b8b75435d65aa0a6ef0eb566ac1890b576c330f64f
-dist/2025-02-18/rustc-nightly-x86_64-unknown-freebsd.tar.xz=725f9e9d25b7ad6f60d5596684964b0c3a63d98a62a2aeda6a134b9f02fdb681
-dist/2025-02-18/rustc-nightly-x86_64-unknown-illumos.tar.gz=86a9034fa275c0fc73d639fe6437fc4d2621bf12897c9f83a81ab6056173a95f
-dist/2025-02-18/rustc-nightly-x86_64-unknown-illumos.tar.xz=4aeef66ad8a908589ddf0d89581a6ca809b7c2a57f06bbda6fd3927b531fe07b
-dist/2025-02-18/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=907aa282fb9f3d96c9fb03dadd62f4ea766e1242fe19106ae331a4f49a9b20f0
-dist/2025-02-18/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=e63d13a6acd596ebfd7bf65b292eedd2a5e260b536ca11517a3fe1d8e6a6241f
-dist/2025-02-18/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=b7bee098c32b321551f68e96e002f85e3a0323c864aa7f65641a58ae24f4238e
-dist/2025-02-18/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=e5c22c2fab89c7ba548b11104c54e8f82cafb1979ba73a318682bb10ed9e4fb9
-dist/2025-02-18/rustc-nightly-x86_64-unknown-netbsd.tar.gz=7bf40bffe95437244f6f8a5fde69499f42d2b716e166115530fbcdbdcd837887
-dist/2025-02-18/rustc-nightly-x86_64-unknown-netbsd.tar.xz=0adeaa382f289233ffc9229e116a340ac03a861f0fdbb5bd35aaf5d0d7370877
\ No newline at end of file
+dist/2025-04-02/rustc-beta-aarch64-apple-darwin.tar.gz=42fbc48c6f9034c1d47029491e0adc7aaa1adecf429e22ea9eb6d36225ed13e7
+dist/2025-04-02/rustc-beta-aarch64-apple-darwin.tar.xz=08f88363fd42d66d537c0a296502f94c3a3fecf59a004613c9acff33eb0b0207
+dist/2025-04-02/rustc-beta-aarch64-pc-windows-msvc.tar.gz=ea47adaa63abd18bf0c11cdb381eefb2874994527005cbccc0dcace33191f9c6
+dist/2025-04-02/rustc-beta-aarch64-pc-windows-msvc.tar.xz=cefea68c789907a45f0bd4233da2e3406287ac55d1c33f8612ec1aa006b853f0
+dist/2025-04-02/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=38fa4ce395641a988247ee58c334389eda62fc1d3c0fb45157f24578319925d8
+dist/2025-04-02/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=d8d0b459acdff2a32f8c40707bf5a17b71ce86fb5ee9ad61690cba8f8227bbfc
+dist/2025-04-02/rustc-beta-aarch64-unknown-linux-musl.tar.gz=41f01647a80a7f21b85fe660af9e7964ad34f0e909d1e58c9e28e102a796791f
+dist/2025-04-02/rustc-beta-aarch64-unknown-linux-musl.tar.xz=8436eddf40ad5bf61153f24c887fb0f0e878bcc403095719b35f3147328d6406
+dist/2025-04-02/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=07ee5588005a18477a7de89321e6527ee5f10af00e9c4eeb2a8c666f79d3d606
+dist/2025-04-02/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=8a95664cef49c1e45b2ae61ec464a5be976e4cecd2b502a050f95b9eb25dd4c7
+dist/2025-04-02/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=b9b186ea9bee58a646ce8c4c384fc4cb528c73c1fee3ea3f5028fd4b3fddab3a
+dist/2025-04-02/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=9f62c2ea5b67c14ab804267d449ded07c8b551536886099b02b942ce2d641790
+dist/2025-04-02/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=f07363ad0dff8b965dc10543f27cfd923266dea6284ebbb1d1b59b77f5ae2b61
+dist/2025-04-02/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=a31afc234645a7dc5dc47f05bb5321fea12931278433df834def303cdea9f52d
+dist/2025-04-02/rustc-beta-i686-pc-windows-gnu.tar.gz=f396061e8faaf66edea34b0855e2d3760fc0fd5c75e99696b50b2d4f310e11e0
+dist/2025-04-02/rustc-beta-i686-pc-windows-gnu.tar.xz=0f95f9170c5b211db29c3baac9341ef61de83511fe0000b8aae65aaf90041ae6
+dist/2025-04-02/rustc-beta-i686-pc-windows-msvc.tar.gz=82b7d1136d1b6f3d229fc77eac19d2cbfb3a46de472345b0ec3ebc152872164f
+dist/2025-04-02/rustc-beta-i686-pc-windows-msvc.tar.xz=565bde72132e77617059da66edf9262f728336a2cc2c3c7cf4d61e0a4b5e681a
+dist/2025-04-02/rustc-beta-i686-unknown-linux-gnu.tar.gz=8a3abc2a8aee8fa30699f51a216b29b41b2242143646d0f560f89bf72a0e285c
+dist/2025-04-02/rustc-beta-i686-unknown-linux-gnu.tar.xz=7d47cf99aa5fd3b5bc2caa918b4eaba793b6d38252a72fa7be631c8db27c8525
+dist/2025-04-02/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=0654cf14bd3302d001fa00fe73cb7c597206c6897978b3aeefd00e9325a8bdad
+dist/2025-04-02/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=6cd5c3ccb643a912d738239c0ad7464ee755cd81f45a26a9d3aa5ceeff569ba3
+dist/2025-04-02/rustc-beta-loongarch64-unknown-linux-musl.tar.gz=e3c0c5c52b04dd060f3a70b0c936dfb5c70ac29256361a491df9c898259dd551
+dist/2025-04-02/rustc-beta-loongarch64-unknown-linux-musl.tar.xz=83a9bc8f9a61b2a7fedddbdfb253aa078bc9896f179ec9b1d1bd918e7de34663
+dist/2025-04-02/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=21efa7a67647df8aa99e40317c798895321d09c48b8453e51eef1635c20e9c47
+dist/2025-04-02/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=56203ed9d3bbbab33e2825db7c72cfbe4f857f68dc98072cc98280cc4f1110d6
+dist/2025-04-02/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=76c343aa3f5c74e1419e3f2f79dd3a2091fad8f6db644cf14f7aef036c8369d0
+dist/2025-04-02/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=e9c7b97a407127e51fa49ca94c5f22c59f2f325848d55e6160d6dcf7ff690f91
+dist/2025-04-02/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=27935ff4136141519b4e7b37b55253960b7fa16f5cd751d731ed85019432247b
+dist/2025-04-02/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=fd37c12a55055bc4a2f0e002b3126e6396df8d49254b2a8a7a45354aac46bb2c
+dist/2025-04-02/rustc-beta-powerpc64le-unknown-linux-musl.tar.gz=cbeba9993d03c6c0c2c508414bee04665abb9c084c736b39c5b8d38c8f63402d
+dist/2025-04-02/rustc-beta-powerpc64le-unknown-linux-musl.tar.xz=e92f69d85929c81e3c91b2ab45eec418afc65edf6f8bf9383148a98b052353df
+dist/2025-04-02/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=31a8ae1e64fb86a499518d7711595d653db56527aaedea06bc2bbcb912568844
+dist/2025-04-02/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=7d001ad6c4825d5323813ed19747cc3e3d2dcbbe76317329a52127b3de37ee88
+dist/2025-04-02/rustc-beta-s390x-unknown-linux-gnu.tar.gz=c69d15e75d51caa0cf77fbe149d43b62c327896bdeb0c6c73fa7240404289862
+dist/2025-04-02/rustc-beta-s390x-unknown-linux-gnu.tar.xz=cf80772ba9eed4885a28aab38323f0ed24ab220339a3b8a148b7c27860c48c19
+dist/2025-04-02/rustc-beta-x86_64-apple-darwin.tar.gz=be22d207f8fd4722d69f6fdc56c57618ec01c54c5b6f3a8506c62583259d433a
+dist/2025-04-02/rustc-beta-x86_64-apple-darwin.tar.xz=04feea9824748ae01b4f4f85d15adc5baee23c996c22de86041888466ae69512
+dist/2025-04-02/rustc-beta-x86_64-pc-windows-gnu.tar.gz=8c75005f0309d30e7c272adce173adb253874ce881b347946b6ffe5a07067439
+dist/2025-04-02/rustc-beta-x86_64-pc-windows-gnu.tar.xz=7b87c4ab5291d9ad3670f4e9ee98fe9f6f877ab8d4952109d7e5e9d20181a700
+dist/2025-04-02/rustc-beta-x86_64-pc-windows-msvc.tar.gz=a96d89ba655db5317dd51ffa2ebb81b7bdb76b19cf12de36e9d0aba2c5877ae2
+dist/2025-04-02/rustc-beta-x86_64-pc-windows-msvc.tar.xz=84bcfd763eba610c78223697393ea97f1f70e567a44b8cfe22db79f1cade4201
+dist/2025-04-02/rustc-beta-x86_64-unknown-freebsd.tar.gz=95ff7349cf12e49028256c06c8517719cada2720d4db80bfe7531289bbcdbde9
+dist/2025-04-02/rustc-beta-x86_64-unknown-freebsd.tar.xz=c8d0147c625faa5ce0e75c2509827bc4b190ad286e41411bce92023e00eb7a1d
+dist/2025-04-02/rustc-beta-x86_64-unknown-illumos.tar.gz=4be80235a110028d64404e532eb20af37e46db72a7ac3a0cf7c94ddf463c461f
+dist/2025-04-02/rustc-beta-x86_64-unknown-illumos.tar.xz=b18ea9a5c262c2f7505305110473cc15bd2c4ed9d583f07c15635406c050be08
+dist/2025-04-02/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=234027a0075224ea157efaf39173ece43f9ca7d69d86e4790a2a038f7e6d98a6
+dist/2025-04-02/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=308a8ee2855a6471db3b3b64cb06e355e31d0d617ebc9f30757bb7db5f6fc7c0
+dist/2025-04-02/rustc-beta-x86_64-unknown-linux-musl.tar.gz=10f39cc94f39bcf17d0fa3b8efeb4db72408fba694e5eb0f175e7465f6d2de49
+dist/2025-04-02/rustc-beta-x86_64-unknown-linux-musl.tar.xz=6b0d16b46347fdbcddfafad8209df19515059eddce1e048ecf1585341fa1e586
+dist/2025-04-02/rustc-beta-x86_64-unknown-netbsd.tar.gz=09f482425c92396f7e4ae3baf625dbcad1d886d82ecfb605b50393abdc23ce15
+dist/2025-04-02/rustc-beta-x86_64-unknown-netbsd.tar.xz=bac2f1a493bc2c5fa6cab1f58ff536cbeba55f77141b34636bfded9e3ff167b5
+dist/2025-04-02/rust-std-beta-aarch64-apple-darwin.tar.gz=8875ade1dd8ba0bca0c12860a076df1f089195a52adc546679025c405bef4dd1
+dist/2025-04-02/rust-std-beta-aarch64-apple-darwin.tar.xz=0a0593ab4c95802b0ed810c0442e13ad9304712c2f7c30a30c734523a7448d8a
+dist/2025-04-02/rust-std-beta-aarch64-apple-ios.tar.gz=839086e20098c305adcdf9103cdf3f29a14c4140b4c1b728723e7aedad966883
+dist/2025-04-02/rust-std-beta-aarch64-apple-ios.tar.xz=70f1832193e77a2018088943b531bdbacbe5404d5d7a34393e03f40329e742ce
+dist/2025-04-02/rust-std-beta-aarch64-apple-ios-macabi.tar.gz=94adeb2e63a91c09001facbc554678227a3717748104424e4fea71db3d5a16be
+dist/2025-04-02/rust-std-beta-aarch64-apple-ios-macabi.tar.xz=73c9bb75eb6fa4cf613c7a2b0e237472e144a1469cb043194ad7802052149fee
+dist/2025-04-02/rust-std-beta-aarch64-apple-ios-sim.tar.gz=0e01ed2620887b893687758d62422f661429e3c4566ff52d967463eca89f54c5
+dist/2025-04-02/rust-std-beta-aarch64-apple-ios-sim.tar.xz=c26beb8ea9f11845ce79d4f0ec2616ce82dfbc4fefadfc7f94a1df17f4d5bec2
+dist/2025-04-02/rust-std-beta-aarch64-linux-android.tar.gz=64047673efa9d9bad660e2a44f82e6f929c881fe205523bff10a549505d12b72
+dist/2025-04-02/rust-std-beta-aarch64-linux-android.tar.xz=0e4c6b76e8d92023533aef6fe377c9bd45ef9c1da517eda7bfefec85b966780b
+dist/2025-04-02/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=a25c50a86e5d674600cec5bd9e7939bf36b0afa766445b0d71673431388d285c
+dist/2025-04-02/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=8060a4c5337fa6c34b3f08ddb8886beeb5bafd2b02544b08a7cfcb466a27a972
+dist/2025-04-02/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=efd76703934ae0187308eec9b3439abea0dd4437ac353d5dc07d92f9440ab9ee
+dist/2025-04-02/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=007462f554b0c6d2b165d727bf72b1ad4347a53869d672fcbf48db2c1dcf128d
+dist/2025-04-02/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=e0dc54be7890edef123d2dc31f0dcddd1c807cc060a34f475093cab79100d9fd
+dist/2025-04-02/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=01c06c1d61c512a034a109f50f957e4496639549837b63464acb4fb24ff65e09
+dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=2042d37b09618379dd91125d20803e2d97d5f3f3794e01ed27597a0f3b27c102
+dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=568f0b8da190daf78cd8573b0408db2ecc2c07b1cb1fa463239581963738e9de
+dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=386b1e4786dbfe342626cde4c3708abd04d9862d69717c7acd5dfe82427e38f9
+dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=781d0f9417e1b3d33d95e3c5b82ba7e481a610dc468345119e09a52b1d170045
+dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=8673d059524ac141a8907decfda36c8afac81fd36dd75f78df750a6d52ada221
+dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=8e8afe45e9bb84ebc3e02f0b4b71dbcec7c844128329d31067303b86113c3439
+dist/2025-04-02/rust-std-beta-aarch64-unknown-none.tar.gz=72e1dce3c1f821b6018ec155bff250b941afcfcf1697b440a69822b10e929b94
+dist/2025-04-02/rust-std-beta-aarch64-unknown-none.tar.xz=7030883ad3ca170a061972707c488fc25d4dc8ab0f60a1b9b54240e42ca713ba
+dist/2025-04-02/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=28f87a505ca4e2c33015338d73cfdf5c2fdb1f5775f82ec432d033a36880351d
+dist/2025-04-02/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=45669a09671c183d702a31b6ecf095e8f422797c4e242063c7864180c6f657a4
+dist/2025-04-02/rust-std-beta-aarch64-unknown-uefi.tar.gz=1ad54cabda8bfabfd93e16c564c0950c26e1502662d5f4ce3b33b4ee265b9a2d
+dist/2025-04-02/rust-std-beta-aarch64-unknown-uefi.tar.xz=a79f9d7eb4297994b2e87d48106a959c82bc4387433e5e86dc8caddde29a8a4e
+dist/2025-04-02/rust-std-beta-arm-linux-androideabi.tar.gz=75192092fa7a40051a70a843cf75513de2c50d66927f16b122f7417c1d4f25e7
+dist/2025-04-02/rust-std-beta-arm-linux-androideabi.tar.xz=843dde45dfa49b5cc97266c61d8e58dfb22dbf2288e6e8baaef769eaf59675cc
+dist/2025-04-02/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=03ccaa5e246502fc61fea1e0b33f5c60b5895cd0b5b932bf640d62e97164b457
+dist/2025-04-02/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=a73525dcab3a0f3bc7064c8a6cdeb9b0e5b359501cb7e8fe20075a0e97b2a5ba
+dist/2025-04-02/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=8c851fc122d14beee962e15fdb95c2873769805180be30723f418d84cbc0a8b8
+dist/2025-04-02/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=8524ad1b7723a4a5898837d5b526fb11ffcd039b2c4835a2e139071f6cfd4e9f
+dist/2025-04-02/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=b108ec4460d4f6ca79813e6d2d4cb7061fa522a990333fb9f4f927b0fc659624
+dist/2025-04-02/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=0bdb617dfa833c62c03f5bfd2f06ed3ca1479908d860f888d661794188bd57d6
+dist/2025-04-02/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=19f9fff71344f7a42f958c3efec720e4b2e0d67ba36a5fd66946e74811259f2b
+dist/2025-04-02/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=0cdfe9b4a8bc4b63637cfd9766c3e0e1d3dcd6d2e82fe35f57973a0081e630ec
+dist/2025-04-02/rust-std-beta-arm64ec-pc-windows-msvc.tar.gz=a8490374598bbfa42931bbfba51ecc0186c476217eb79408ae6b80a4ba6de9f2
+dist/2025-04-02/rust-std-beta-arm64ec-pc-windows-msvc.tar.xz=2bc2838320667f060c140345d1c26aedf90bf5efb1f72e6722b74d32f876901c
+dist/2025-04-02/rust-std-beta-armebv7r-none-eabi.tar.gz=9a237e1dbd2e3b555aa3932351d1c20a0f9f2f06e810abd254b5ca152aace687
+dist/2025-04-02/rust-std-beta-armebv7r-none-eabi.tar.xz=f4978bf9af719f0b6e8300ea862fe617e983e5443a46c769d60d5e8c4d556ba8
+dist/2025-04-02/rust-std-beta-armebv7r-none-eabihf.tar.gz=c1476718625d5d5d42b60faa9ade845272b0b71e91d77a9cdd271c4682c900d2
+dist/2025-04-02/rust-std-beta-armebv7r-none-eabihf.tar.xz=f8ab07e99983fc7395841cc9ed7ce7cfaedd87bfb91214bd83508ad96aef0c0b
+dist/2025-04-02/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=649071a7de4792ff75da59ca421ea1cb364c011db97e73c480982a5f9f06b8aa
+dist/2025-04-02/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=529aac0b0a385fa5ddb76a88eb6923bcc981679caab2d1c374d443383c99f52a
+dist/2025-04-02/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=8bdf3412b0b557485099db86afcdf58293bfd4c09c4b360c2d9733788b612122
+dist/2025-04-02/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=5d5a4ebed984a0930b214ec0b11e20fd9a7b8d5dc2d00985b75a77c8febcf441
+dist/2025-04-02/rust-std-beta-armv7-linux-androideabi.tar.gz=2c03cbb393641876bebad9b76465ac7f96adb82c14dcc9b5bc01a82e5110b892
+dist/2025-04-02/rust-std-beta-armv7-linux-androideabi.tar.xz=67d86fa728178c30cd7a33e0c488c32f58ae0caeb9a982370e080ea38853830b
+dist/2025-04-02/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=3737dd5f80f35f3fecf5cd8324c9226f45bb0bfd040998d91509a2c6fd8967f1
+dist/2025-04-02/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=8f9f710c92af058d5a07c93b4cfd45b7d30e63ab79bea7f79530537aae2dd836
+dist/2025-04-02/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=6ecb3e238e125e88851dba9711b2b32f4de1da55de36a62373bfcc42d001fa0b
+dist/2025-04-02/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=7d6807d24afe4825b77c1cb74c1412b814cf2508f5b40debb55b3f264e02eb6a
+dist/2025-04-02/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=a15fccced78065f748a5c4f66763b8940ae3e52b5048b5ee1fab6b0b7b40c701
+dist/2025-04-02/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=20bc43c1b5742a9c7a97ade055441ca1ca153dab9602db3ffaf1ac518713568e
+dist/2025-04-02/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=b01929a0f18b1a41b65307a04d1273d2197df83b3c124f80659ef8fa4f8c4577
+dist/2025-04-02/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=2a13350da7c632d3878ca8da8a7d0bda60c850df8e5d824956082b524eb136fe
+dist/2025-04-02/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=11bc9fd437be07cb454182b0d7b287ec030f7d8904f096b73beda6480ba33285
+dist/2025-04-02/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=31e06feb45173fec8e58cf92216e44d556587fe2ed866102206e23514c73d3f0
+dist/2025-04-02/rust-std-beta-armv7a-none-eabi.tar.gz=aebbae792c070adea3f10135c02b2cf5d623b84e765ec3a72c89275f53a85384
+dist/2025-04-02/rust-std-beta-armv7a-none-eabi.tar.xz=e80dcb152e7a8337fbbff6a5c8dfcd9c6da4b753da6b14e63fe7c15cc0836359
+dist/2025-04-02/rust-std-beta-armv7r-none-eabi.tar.gz=e79846c1203d5d375c7c1cff1c843cb6fcd4e33bbc71b2363e12fc900bbd72bd
+dist/2025-04-02/rust-std-beta-armv7r-none-eabi.tar.xz=0e24e48461cc46edef0237e38480ac806d0521c73ea366668e731f29b638d7c9
+dist/2025-04-02/rust-std-beta-armv7r-none-eabihf.tar.gz=fd2a9b48ea203b44567cfdcfcfb21d5d803896fdfdc5f3aa191e3fa7472b98db
+dist/2025-04-02/rust-std-beta-armv7r-none-eabihf.tar.xz=2b85d461bed34a97cf832a7c0e1d4179d7800ef47523a8e31d635b8de5dd44a7
+dist/2025-04-02/rust-std-beta-i586-unknown-linux-gnu.tar.gz=cab412c30b27060cdcb29adb947dc070875813726707dff121c4a1aa8615646d
+dist/2025-04-02/rust-std-beta-i586-unknown-linux-gnu.tar.xz=1b8d469fbb8903a5f4f5eb6ccee7bdf28cc56137b6b212fdfa1aed647f4c347b
+dist/2025-04-02/rust-std-beta-i586-unknown-linux-musl.tar.gz=93fa0383e32f18567c3c156f3cddde1fa4296003f98cdd22b0b5628d69d5208a
+dist/2025-04-02/rust-std-beta-i586-unknown-linux-musl.tar.xz=71ae00b01ffbfdc6654d0fd14df204adb7d499ac71e59c93affff91d58833d88
+dist/2025-04-02/rust-std-beta-i686-linux-android.tar.gz=4c6f4764e284ff29958417295ddc5d3316072fc9eac87dfed8b694c237aa4f88
+dist/2025-04-02/rust-std-beta-i686-linux-android.tar.xz=f471a7abb2d447f668f01973be4712e20c6dd29b210a96517b277e62c6d7de07
+dist/2025-04-02/rust-std-beta-i686-pc-windows-gnu.tar.gz=0c5efb9792502fc08174b2556f5c91f3edbad6e02de5e230f39c5fa011fc935c
+dist/2025-04-02/rust-std-beta-i686-pc-windows-gnu.tar.xz=b6a87360e7be832288e59239d41e809db01710ccae5ef37bcbe7b0eb1d311e66
+dist/2025-04-02/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=0429745cd95a198a7a42a1ce0c7ab2d502f3ff3eee81104fe6d5d4d5dab9447e
+dist/2025-04-02/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=bcb43c9e2d4a49c18d39e041d28021f2302707ae9ac20ef37f4d467fd2cd3975
+dist/2025-04-02/rust-std-beta-i686-pc-windows-msvc.tar.gz=e1d8c40e61701c6bfd519125169cc1ab1d60e9a58238351bbeda0ccc5522cc49
+dist/2025-04-02/rust-std-beta-i686-pc-windows-msvc.tar.xz=1f87f343a90f6e88cb3173d52f4f88d8abdb0c1a613681c92675c1acc340aa54
+dist/2025-04-02/rust-std-beta-i686-unknown-freebsd.tar.gz=5862f33548bef1aa21b3d63caefa12ee34775cb378f89c4dc161e081a773d11e
+dist/2025-04-02/rust-std-beta-i686-unknown-freebsd.tar.xz=ed3460948031d0c4e97f7b1b77062f388d133db2b2212518eabd3198e72c031c
+dist/2025-04-02/rust-std-beta-i686-unknown-linux-gnu.tar.gz=3a6edd9f412a274e372c9555b6758d540d06ac08efd21ce95df1ed4d30418afd
+dist/2025-04-02/rust-std-beta-i686-unknown-linux-gnu.tar.xz=8338baaa50b9cb08a28f7bb21a22deef849f8809282c661e48c486a168b6249e
+dist/2025-04-02/rust-std-beta-i686-unknown-linux-musl.tar.gz=56ab80fc6cb75a0d66c477e76f87918645bc3b616cf704306820832681022768
+dist/2025-04-02/rust-std-beta-i686-unknown-linux-musl.tar.xz=94efb810dbee977ecb3ff5a42a5a620d720c237da58d974ba1f376c99947baf5
+dist/2025-04-02/rust-std-beta-i686-unknown-uefi.tar.gz=64cb107065bde9b30c78b9b342211c4e6cd2c3ed726155dacfcf5958ba869a82
+dist/2025-04-02/rust-std-beta-i686-unknown-uefi.tar.xz=ff1bc215b4aba25f59eeee8285967e24b78f6965473ea8bb30186ab55804f88a
+dist/2025-04-02/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=da1d33b266e1dd277f97f63228843765706f26c9f75c4b5171f49c2762fed870
+dist/2025-04-02/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=8309c9c4a03df90eb53116b5c5c4870d103911227848919580a48e5e85954709
+dist/2025-04-02/rust-std-beta-loongarch64-unknown-linux-musl.tar.gz=26a3115d5354f878f80bef1c83a44af185e2780882e17143ca57aff078d123a0
+dist/2025-04-02/rust-std-beta-loongarch64-unknown-linux-musl.tar.xz=12431c3b50276f352a3ea71c74db279cd03c2edfb3edf743f81774d4274f7ef9
+dist/2025-04-02/rust-std-beta-loongarch64-unknown-none.tar.gz=ac67b23f84d09ab17d26f30deb38a128ccf812a561738327effe48ecd0caa319
+dist/2025-04-02/rust-std-beta-loongarch64-unknown-none.tar.xz=5508b02465d3dbb40512a142eabb27817807d2af153089f7d05a0af355fdb245
+dist/2025-04-02/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=a79a59139e13166cb1121d703cee113bf92821f937d433cb9a2c00567280a4e2
+dist/2025-04-02/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=8c3b5501050f57125cc89e6525b780ca0e18d2d5318f779894ab97efef761fb3
+dist/2025-04-02/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=84a48148eb313f236f85a4907af615b7af4c3ce3d9065ffe0db54458852690ab
+dist/2025-04-02/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=26281622332b438bc43b8f46921153a45c6236a4c0939c76fdb4d9fb3d29cbbb
+dist/2025-04-02/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=0eef233c871404b913c6458d8005d362e3c24fcb0670ac49a7e67b1a503b4b29
+dist/2025-04-02/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=b96422b0f33446abee203160a22e9bac8861e1c7988b2cef463276743001fc7c
+dist/2025-04-02/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=18db97406a6e644734c7890991cb3006fabe1e1a185f89d108d28a992ed7c17c
+dist/2025-04-02/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=eea42655b5335643905acaa3d8ff1774e2c1a39ffde363c2073a8636c153087a
+dist/2025-04-02/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=5feaf6f3859204979fb4dab03fc93428abd103d61822d6e4e9a2f5d6d155213a
+dist/2025-04-02/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=98f8e695253c9dad3d82638bd69c084a3e7a96d17eb1dba0f90a42df993de864
+dist/2025-04-02/rust-std-beta-powerpc64le-unknown-linux-musl.tar.gz=e028f2ec967ecee5d9e7b48058209428ed220c5da2c00f2753f8d4e98951e168
+dist/2025-04-02/rust-std-beta-powerpc64le-unknown-linux-musl.tar.xz=69f508ffcb55347dbb773cfa22a1f7a6362f3aff6a48296b50945422ea82c7b5
+dist/2025-04-02/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=ea30bf48fcb3873db4019ae3d248e1db868e1f7fc49e4549737aae58b3b49b22
+dist/2025-04-02/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=c3724aaa58f812dc8283622f27e215546d8522b6ecdf1d191010dde3a1ba3344
+dist/2025-04-02/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=9d24eb785b66796309c2f03944719fb6b6980ae8fb7ca97084fcfdea0094bcce
+dist/2025-04-02/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=f6b2233474eb64d041e6bd8f1b6dee3eaf775b6b5a7ddec703689352cf88f6a2
+dist/2025-04-02/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=8a5c94055180b9a1226a23c5992a622062ac52cddf91651a91a5d236be46d0c8
+dist/2025-04-02/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=7ea826d6c58fe1ef1c9374aef0cbfec5495daddcda581b231d18397330d9e248
+dist/2025-04-02/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=811881bd5b514c89c316453ea1214fbeccf5388f18468cc83676a879d58f53ab
+dist/2025-04-02/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=9448b7bad586237faa4f090ce8c3de83b62d19fbe37104ae32032d9df709d2e6
+dist/2025-04-02/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=dd9252a03b0a888ee7598a84c20aac721739c2caf9c5b585274d2a30d7fcbcb6
+dist/2025-04-02/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=d1f134647fe0c3efcce80351cf9e4786ca8e3e336c0316b7c28ff07b78907c73
+dist/2025-04-02/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=4f688c40457ba71542438fbc100b62b5f081435567f965512481ccf3d002826d
+dist/2025-04-02/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=a474fddf29c6979e0870c397c19f64de00650893a781eb51d9e136802bfabbfd
+dist/2025-04-02/rust-std-beta-riscv64gc-unknown-linux-musl.tar.gz=7071209fdf0d2605b623ef96c934ed039d1dd95a68c438a8c563530ed48fb4e2
+dist/2025-04-02/rust-std-beta-riscv64gc-unknown-linux-musl.tar.xz=1328504e895dc9bbc36ac697bd5031e0034b2468fc66a91e42b39a4d35d4ea8b
+dist/2025-04-02/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=e7878c1137279790205e62f9c363a6f45e2a8cd9c30702a53478a8104dc87a6b
+dist/2025-04-02/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=f373b1d79547c385a01c2b36951eb3750a4cf3bcaaa213587af9a6b4274dc924
+dist/2025-04-02/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=4832338ebc25d088e30952605b3f6491d96003790df5b10c5c56e29ec69ac646
+dist/2025-04-02/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=d782dac690b3da2b96206809512f1ae82fb4a73ee387d91128ae0d98bf51ef3a
+dist/2025-04-02/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=faccf22845e31101a420796d9065b350092cbee29d755c2369ee36cc7172866f
+dist/2025-04-02/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=f296c5726380b1f2b8603a079e8dfdfa7e4a97a499b1e86874753c312768ab15
+dist/2025-04-02/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=b8a8fd8fda8b99d96d6f890bcd0c9073393441e85a4cda169b6fc7dbb7296984
+dist/2025-04-02/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=923a0530224f0631162f7b86bef79be85f45071f62ca4f5de0588fb5ca6affa8
+dist/2025-04-02/rust-std-beta-sparcv9-sun-solaris.tar.gz=944a83365d3c46313e28b1d3a5b0e52e57ce88b3eaaf0f7f53234d4423ce9ca7
+dist/2025-04-02/rust-std-beta-sparcv9-sun-solaris.tar.xz=be0c983c443f05feb4614d97336755894b3ffc5083d852bd84ee7cd9e5edfa03
+dist/2025-04-02/rust-std-beta-thumbv6m-none-eabi.tar.gz=08905a766352dd259be919aeb366e965dbbd4066c398dc4d26efa333b0ac46b8
+dist/2025-04-02/rust-std-beta-thumbv6m-none-eabi.tar.xz=4fa005107c3d1addb242179c03a804a27d34ca68bd76c092a41a197da56abce1
+dist/2025-04-02/rust-std-beta-thumbv7em-none-eabi.tar.gz=e6ccc1004004ed759b1814daae0b50a3a0adca9786688ef9cc601a0a19edc72a
+dist/2025-04-02/rust-std-beta-thumbv7em-none-eabi.tar.xz=fc23abf9c086a34264bfcfe7c4876ec65ce54f8ca73a98020bb8eab6d2c51d57
+dist/2025-04-02/rust-std-beta-thumbv7em-none-eabihf.tar.gz=e8121551c0529f73796bc157bf916e3608685454a02a81d170a258a7465b5b7c
+dist/2025-04-02/rust-std-beta-thumbv7em-none-eabihf.tar.xz=2695f76447ff5d70aa3cc6b6690267b31b9aa4ddc7c45205e529f92d234483a0
+dist/2025-04-02/rust-std-beta-thumbv7m-none-eabi.tar.gz=36d7fb4edd572c7d73501aab7c89737ee0036d606700c728f430142e91649eb0
+dist/2025-04-02/rust-std-beta-thumbv7m-none-eabi.tar.xz=a6e59eaed0ab3e310852d9a75fc43600c7c2eee0c808224b87bcb8c18df4ada6
+dist/2025-04-02/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=6bc70be43929b77f3508b1872e5b09227aebce1c7c9c943995b5df92cf6d9181
+dist/2025-04-02/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=37b956924534aed1ae7ef9908d38bf724c6903591269136d23e293e17a0d333f
+dist/2025-04-02/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=041562edada0caeea67fe7f3ffb5b9f8c1b506c0d5ee7b657c5ee2afbefba7fa
+dist/2025-04-02/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=8980372a7e9a072b1e0b954569e59df260583a3371daf005c5a83576688562d1
+dist/2025-04-02/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=83f461ac0ebcc05d5cbf67a6585b49dc7b245c8788dc3a75e08a93be41e2615f
+dist/2025-04-02/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=6ac8847ce601c8dfeffff07915de06a605b3c685f81b90f87b092897c2afb973
+dist/2025-04-02/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=bfcd9ff7dc9bb5e95bd563d750240efcbc3bfa1a21a9f9a2786ef37f665b7e43
+dist/2025-04-02/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=4507383395a26d41abd71041b162dfc5e9471a4c624d9fd6ad310e184ef15d01
+dist/2025-04-02/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=b4d1940ea5e24cd6a0ba3906c98d2b03e4a18927619152b43e91832733316258
+dist/2025-04-02/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=45eec7770344beb84cf418cf7818216d123136465785f4742127f6f5a8c5ce27
+dist/2025-04-02/rust-std-beta-wasm32-unknown-emscripten.tar.gz=19bf2f4bf64f874ccfd84b820b7200e83e896c96a396edd7bd10301d2bc89d98
+dist/2025-04-02/rust-std-beta-wasm32-unknown-emscripten.tar.xz=4c616b7bd972c09461f0bccf5009bc574dcfa8bdce2dd97d17fcffd64542e496
+dist/2025-04-02/rust-std-beta-wasm32-unknown-unknown.tar.gz=69bcb61fd0f8bd7d2da225a4525a877cce003afd7fc3d789c385f164959cd41a
+dist/2025-04-02/rust-std-beta-wasm32-unknown-unknown.tar.xz=0372a64eda0c7249ce5fbcbbbf29e145e969b383a73b7c470f0b583720fcdbe2
+dist/2025-04-02/rust-std-beta-wasm32-wasip1.tar.gz=f76a2a3f4702eb781a680ebd4346afb4c26ca2235e62bad144b057860c09b8a8
+dist/2025-04-02/rust-std-beta-wasm32-wasip1.tar.xz=173bc3317b59a01036a9c8e0bccc570fd6f5174d15f94634f53d81dec3d2cd68
+dist/2025-04-02/rust-std-beta-wasm32-wasip1-threads.tar.gz=18e05380478ed0b3f76d9062fade2be2e66c039dcc470ffb01be3c8dffc79995
+dist/2025-04-02/rust-std-beta-wasm32-wasip1-threads.tar.xz=3d477eb85308f73d1081d6dd3e54577be4bd84f291a50af0e3be15fa8aa36db6
+dist/2025-04-02/rust-std-beta-wasm32-wasip2.tar.gz=3444883960a9f8b831d1f26ee17ef082a2029cdc2e9b45ce5af4d6565d3a526e
+dist/2025-04-02/rust-std-beta-wasm32-wasip2.tar.xz=867361c7ba912b404c426807a60625a1f830707a172f7da139c1a892aa85bf35
+dist/2025-04-02/rust-std-beta-wasm32v1-none.tar.gz=d15017a323c662a1e8c65f51e66151138c2255cd8842a67e990000606dac839f
+dist/2025-04-02/rust-std-beta-wasm32v1-none.tar.xz=f3b32484ef287317187ca0bd5245b1793ae40d50290a2882419da8503b8243f3
+dist/2025-04-02/rust-std-beta-x86_64-apple-darwin.tar.gz=179be6a29fcf16b4c18775208569a051f2f5a38558e751d2dda0a42027868843
+dist/2025-04-02/rust-std-beta-x86_64-apple-darwin.tar.xz=912f7f8d7117a5cac85dffee5ffd9f2c1cf237477bb0f9e1127afff1f0cd4757
+dist/2025-04-02/rust-std-beta-x86_64-apple-ios.tar.gz=9d2f3230bd82ba9d45e572b45ec63c63cfb592dba6311b6a16de075f18c86999
+dist/2025-04-02/rust-std-beta-x86_64-apple-ios.tar.xz=c8ff77db2d081444ab5167764465beb33046cc81cf2e8dbbd8e9a7328306762c
+dist/2025-04-02/rust-std-beta-x86_64-apple-ios-macabi.tar.gz=76c9b2ae710fed611a2294a5e4bb6597b07d78f0bbd3a5a0d15c3320f38a0017
+dist/2025-04-02/rust-std-beta-x86_64-apple-ios-macabi.tar.xz=b9c485a3824c971a42c10af26cf06c539c34fa429e92601a1978280867029e62
+dist/2025-04-02/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=a223c08b88c768d97bf9f071c74d9548acf00bbb097b8c8427c2ec87ca205597
+dist/2025-04-02/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=34ddb3db8a71edabb4d0fd8d52a164dbca5a5cd96d6ba131e7d439c333726f78
+dist/2025-04-02/rust-std-beta-x86_64-linux-android.tar.gz=9ba28bf95c75ca0d69461d1c044902443053b64678b540967a97c7cd2eb7cc4c
+dist/2025-04-02/rust-std-beta-x86_64-linux-android.tar.xz=09e35188a801371a55abeb9e2ee455ebd26d41b8eb561b8016ecacfc7ba20c90
+dist/2025-04-02/rust-std-beta-x86_64-pc-solaris.tar.gz=c1f2fb4b90cf258dfa1a52167ba925b583dc889ec1c3c48958560ff3b7b79b13
+dist/2025-04-02/rust-std-beta-x86_64-pc-solaris.tar.xz=d71f2bade21f751d9592e865ce3722b5d3b9abc49e55ca9d04c02d658360b6ad
+dist/2025-04-02/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=691c23504582e6db1cf883f52b5378aad3c42da7e2d2237e54601be9c8d16cac
+dist/2025-04-02/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=22e7327c5ba22863cb62cc5331862b8c2b4b10a732637729b5e1504034aa2cf1
+dist/2025-04-02/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=81b7dda817a7dbc8b33542c356e0c5e5605b7c60a2fee13f4a266c8d970a3f54
+dist/2025-04-02/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=09e4c9804f7489b337ccf66426e18e7522dcba24234b289a39eb63c8242353d0
+dist/2025-04-02/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=a8188567321462309fb63af38f652c6a7448ebaae1425b9ec20d2fe2a12e8896
+dist/2025-04-02/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=5284f85dce61b2b021888b6b82995aa7b4a14a979b42b83499a810c261fc183e
+dist/2025-04-02/rust-std-beta-x86_64-unknown-freebsd.tar.gz=eb57c8ca7f515386d60a88e56443e377aae70e185ac52a62869e115c636a2bcc
+dist/2025-04-02/rust-std-beta-x86_64-unknown-freebsd.tar.xz=8bef59b74196fa9f7839bb491f6b32d0761a45c8d7178980ee3afd80231b836e
+dist/2025-04-02/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=f43f402881f4558e3df4a7ace68ba80caa9354cfa5a8b1efac89f95e38386253
+dist/2025-04-02/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=ea7d09c015c057591ff51b808cca9c8c1d973de3a9033fe42c1bf34d748d03a6
+dist/2025-04-02/rust-std-beta-x86_64-unknown-illumos.tar.gz=a4835455348bc5b154b1bba63aa03d2294713589214b50d3babae3e0f9918a3c
+dist/2025-04-02/rust-std-beta-x86_64-unknown-illumos.tar.xz=711920e7491332251fb672abdc7685fa940f863d8e182e2ae9d9347d7fa6a725
+dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=1b8324839c0e10e410f29bd471f6c49eb4710adbe172d6bef3e619ae95d47d02
+dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=223b41f16a80b9c404f5af9a194b7414ef354681f911839353f24b44eed91494
+dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=6d8d8d9fd6336de0ebcb58fa85aa0d11e62a60d6c6ca01d71da0bdf668d216c1
+dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=033df93011b4461cde64c4230c495bad1523b9b38f5b0de56dd928c1da85b577
+dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=70a441c0cf8ca25abc1f722c1db5dde8b5fd3b90c767895b7518fc58c2678390
+dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=b5584d6d0031f8230a40f5ed76570ab1396c8997c3e957ca159d72a5dc201a2d
+dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=2596cdc3708d82aa93a8a1f595238fe9fd7b5b05a4886e7e390ca3b86d352e7e
+dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=c03901c0c8434b5db244c22145870e7d933b9060af3b23f24a765c755098a3a1
+dist/2025-04-02/rust-std-beta-x86_64-unknown-netbsd.tar.gz=82bc22594dc602b27edf8233bd9c4fbf0323999ce99ff2a7ddd0ce9268647eb1
+dist/2025-04-02/rust-std-beta-x86_64-unknown-netbsd.tar.xz=86f674f5e19a1b1780f06a6d5add06fd4240430233b7c3f5203a4daa5f444673
+dist/2025-04-02/rust-std-beta-x86_64-unknown-none.tar.gz=ca7882354f4274dc405034aa6edbda685b9d76bc6e5905074d2aaf8c35b35a95
+dist/2025-04-02/rust-std-beta-x86_64-unknown-none.tar.xz=ed6c828fdafcf87a68f522379f11c44eff1a4be1bf027d9888d1f17f22e9ca61
+dist/2025-04-02/rust-std-beta-x86_64-unknown-redox.tar.gz=6f8ab182274e2f5b0fa82fdc5c6e3776ba969e6ee6f6098ce6d170f6685f55c2
+dist/2025-04-02/rust-std-beta-x86_64-unknown-redox.tar.xz=ee061d725f657a2e52114f282be0cab1a6e542a0270b11782c36e8737ed84f32
+dist/2025-04-02/rust-std-beta-x86_64-unknown-uefi.tar.gz=0324f537f463738bbdbf40b92423df6c6068f76c583872d6070d6a41c5169dac
+dist/2025-04-02/rust-std-beta-x86_64-unknown-uefi.tar.xz=2cd2727f71b14c06eb0a14fa532e5b3bc66f8b983c021f3201c327606b04511e
+dist/2025-04-02/cargo-beta-aarch64-apple-darwin.tar.gz=76010b5a9f8dff0102a18de75e818c51b915a3bcff428fc48973728577c2ecd3
+dist/2025-04-02/cargo-beta-aarch64-apple-darwin.tar.xz=f0f03ece675cfaa9dd0f00204d7ddd4086a45357f09cac9d800d37bef8d0db33
+dist/2025-04-02/cargo-beta-aarch64-pc-windows-msvc.tar.gz=bf4ab12afcea7911ab973177de83b7bbdfd0000e3090331f31a595d57819ed6d
+dist/2025-04-02/cargo-beta-aarch64-pc-windows-msvc.tar.xz=156fc94166e5f2af91fd9a36c67b545c0eff63dad51fcd81571cce01447c1c1b
+dist/2025-04-02/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=c86bbf8091188ab9f7d41e566ef628a657d66683884333c3851e99edaea6e279
+dist/2025-04-02/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=610383a4efb93ab53cc747ba038888742346499407c982b7bc8c0c41689cf453
+dist/2025-04-02/cargo-beta-aarch64-unknown-linux-musl.tar.gz=7d427779360c9cba5903c2a0183be1c1759cb2c2f2b77bd2f64b409821fabb64
+dist/2025-04-02/cargo-beta-aarch64-unknown-linux-musl.tar.xz=29bda8bd7dcee65315b8c14a527f4e4b4dd678b35dd430591f7c71712ecbd2f9
+dist/2025-04-02/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=ef6d6a810eecb3a38940634b653257070dcfcff52c2d8321fa3a933d41c7ed73
+dist/2025-04-02/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=79796d83949811776aaedc7e6db6d32374c07b8f8d256d9b871de335bf5e7074
+dist/2025-04-02/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=fa93a1285a97453e2aaaf9cf392abb4ff9a419451e925959470166522e54b1dc
+dist/2025-04-02/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=acb69df00475904faccf18729030a70e8ce21543189d48c7102330a98a12edf1
+dist/2025-04-02/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=7141bf32c173d26f34571b2dfb890187d866f113e28b63908841377e48dbc6ab
+dist/2025-04-02/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=249f3c535805fb2510d13338401e9ae96f16e6996e58551025b35676a1147ab5
+dist/2025-04-02/cargo-beta-i686-pc-windows-gnu.tar.gz=fe4f5f35ecac25bc3726ffecbe3e650d51adb9ea13dc5153a0699ea8d8776d13
+dist/2025-04-02/cargo-beta-i686-pc-windows-gnu.tar.xz=b7b8432464eb793e9a651c4c38ee8abe76421a9be7f75e96237a4ef938f927f9
+dist/2025-04-02/cargo-beta-i686-pc-windows-msvc.tar.gz=a283da65d3a75435ff3d05441fd0337472fd16325531086e90b01cc5d5bd221a
+dist/2025-04-02/cargo-beta-i686-pc-windows-msvc.tar.xz=ae19f98c901228ae5c7573cebde4816517bdb8d03dbdc7b92d95518d27d93531
+dist/2025-04-02/cargo-beta-i686-unknown-linux-gnu.tar.gz=e3c5b2560f64c8056ef82ed0cd659d35fda5181f19fa670b962228142398efbc
+dist/2025-04-02/cargo-beta-i686-unknown-linux-gnu.tar.xz=3fc435b8a186f6ec1b7ebc38c92c2e23e1bd786415fc33e7743ef95c37c69b45
+dist/2025-04-02/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=bcab46663be61e979b7a89792d164e182d5482ad9b444a969dbb304c5dad8c8c
+dist/2025-04-02/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=9e2ecb90d85a4aca95211892a6a41fde09ce1e4f44a60caab9aeb61833191d36
+dist/2025-04-02/cargo-beta-loongarch64-unknown-linux-musl.tar.gz=3c5c40f61e85663d03fe51f63d505d8dca73f94bfb3eed29f6e1396b31e0a554
+dist/2025-04-02/cargo-beta-loongarch64-unknown-linux-musl.tar.xz=775c56ce638e0923758ab5f82a87c15b7a1500d10e0be2433af40364a0455d58
+dist/2025-04-02/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=c1a144dc83b673e0375e8f718cde6672ca276dbab9161d7f3e002c6273352c1b
+dist/2025-04-02/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=1b41b3396340c97c122661c95fe54265036e721f1750bad3a8fe4920f6f52b34
+dist/2025-04-02/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=2a43a7682ea3da8b911b09a7bb4a3a75fc3facb64fc952e51ff35c63e6630b75
+dist/2025-04-02/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=73a3383196527e63716de1b1cab233226519873556a755a7e47279f799936116
+dist/2025-04-02/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=d5f521839bd4b258454097cf97b056508e6f9103f7312c93b632ae44ac9f7dc0
+dist/2025-04-02/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=c4fc5ff91bc1054e8497efa53ee6a9a9eb7f06927cd314a681e16b6d46b08440
+dist/2025-04-02/cargo-beta-powerpc64le-unknown-linux-musl.tar.gz=5b0d569fe4ec84d6e7526af9d9794b440e8f1b5fc1b09e951678b09fd3ff97fb
+dist/2025-04-02/cargo-beta-powerpc64le-unknown-linux-musl.tar.xz=e9c68eee5763c624cbe312bc1b50b6c3172eb7997e209371692e7f897d13b03b
+dist/2025-04-02/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=96962461e7f6744a46f18a557a4701d35d6fa3b6d960d854f4c3effe6f2636f8
+dist/2025-04-02/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=4d6029204f930543afeeaf44d9e635692c86c9daaaac6301cccbe076c7facbe5
+dist/2025-04-02/cargo-beta-s390x-unknown-linux-gnu.tar.gz=f40421ea02804c3089420e5ca13838f94fb89c114de9a9e596e9a1207d2166d7
+dist/2025-04-02/cargo-beta-s390x-unknown-linux-gnu.tar.xz=77521eb215cded6886267644661b3357590f20368383f314da8f310197e9679e
+dist/2025-04-02/cargo-beta-x86_64-apple-darwin.tar.gz=0357ed5c9c8ccbe71f89695bffe1604dbd2f451472fc6ea8d8d2dfc93a703b30
+dist/2025-04-02/cargo-beta-x86_64-apple-darwin.tar.xz=6ce4f66b60609f58046138831ae3828ad1d58f8d0b2f515f153c96b690a0134f
+dist/2025-04-02/cargo-beta-x86_64-pc-windows-gnu.tar.gz=8fbf8506fc0c47bb30043c026107c51d6b548fa91320b5bbd2c608e191bdc007
+dist/2025-04-02/cargo-beta-x86_64-pc-windows-gnu.tar.xz=bb57df35e6d73b0b0bba58801d66febfed03f0b3f74085eb50ef8b5ea3fdbb40
+dist/2025-04-02/cargo-beta-x86_64-pc-windows-msvc.tar.gz=0bec5e9059c4b3035f636017c1586653d372f03969bcd4d80c0eaee52f01a2ac
+dist/2025-04-02/cargo-beta-x86_64-pc-windows-msvc.tar.xz=3f836d3027d7ed25655f43262b126311bf014629dadc4a860f00302bc468e752
+dist/2025-04-02/cargo-beta-x86_64-unknown-freebsd.tar.gz=0f60566416471c38350c12f066bb512eca65a66319f5ee7fdbb60464d70661fa
+dist/2025-04-02/cargo-beta-x86_64-unknown-freebsd.tar.xz=eae168df54ddfe95db669c205ae97baa902056722856fa174758ebd058168a95
+dist/2025-04-02/cargo-beta-x86_64-unknown-illumos.tar.gz=816eb91ac3858043f58075fc48fc2e90d0427c58b6283be589d337a7f0ddc9df
+dist/2025-04-02/cargo-beta-x86_64-unknown-illumos.tar.xz=faba548d376309b71bcdae49f7089705be951f72a84ef68362aa6d865d40ebf9
+dist/2025-04-02/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=1fe7e9d2c5a733acdaed418011c1fc31c3036e5299e8f9288ddeac43780fa35e
+dist/2025-04-02/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=7a39bd08e46d3e19da81c02ea3bb46bd1750a3ac1d1db8fb5db852cde14cdd72
+dist/2025-04-02/cargo-beta-x86_64-unknown-linux-musl.tar.gz=00df62b75e1811fd4fcc827b531e7ad94a73fcc37318d0aed28796d902b33568
+dist/2025-04-02/cargo-beta-x86_64-unknown-linux-musl.tar.xz=874084ab37814ddf50ef423e22f0721e5c24acd953ed02cf83432d2372606a5f
+dist/2025-04-02/cargo-beta-x86_64-unknown-netbsd.tar.gz=7b4467e398bd34f94912c56863ae83b45415bbf612b3be15624a6a410c27ff2a
+dist/2025-04-02/cargo-beta-x86_64-unknown-netbsd.tar.xz=75e7ac498a8e617bb907c26f2a3bba9a1e9a22af1c0946f88c7bd53c28790ffb
+dist/2025-04-02/clippy-beta-aarch64-apple-darwin.tar.gz=0f5a8a6a96b8785beae1fc9476374d060632dcc4c17a4335031425ee8e2dec48
+dist/2025-04-02/clippy-beta-aarch64-apple-darwin.tar.xz=aed266be1799ae3e95099d491c3b20b731b2094bc8388c6ac3e782667b58ca6f
+dist/2025-04-02/clippy-beta-aarch64-pc-windows-msvc.tar.gz=0ca97501432918d43aa9bed9b58cd4f1d0d738970e09d6c037ce967519b2b13f
+dist/2025-04-02/clippy-beta-aarch64-pc-windows-msvc.tar.xz=c64edd87358c1ecb9e01b204977edaf0307cc939a3dd3ae62f151c153ac2019b
+dist/2025-04-02/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=7bfdd371ed44a32e50ecd6baf107796d5a77ca3cce0bd58bc5882afd98ca0edf
+dist/2025-04-02/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=cf49acab8153fb65867a9c44eabb7f156f85e9818b6f49453067ce0764036919
+dist/2025-04-02/clippy-beta-aarch64-unknown-linux-musl.tar.gz=bfb20f832ba30a4840f0d4898d27cf69b5717a78bd71b20270f8ddd66c48bc69
+dist/2025-04-02/clippy-beta-aarch64-unknown-linux-musl.tar.xz=54081690d35c39267a49d991e5e0c16043261b6969c49f23c2be44e46c3bfcdf
+dist/2025-04-02/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=3d88b69d6c67c58b09be9d679cfbe8ee449b9de419e950edcffd4637ded46cac
+dist/2025-04-02/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=67843ea0aeaab167029818669074e8bdc46a7e1c269a15580cdfe44a7d2ba96b
+dist/2025-04-02/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=46e9efe50418a035ddabf9a6467b6b0ef20453816c4b6dfd46fa1342bdc42167
+dist/2025-04-02/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=3b27dc434e88280bbc89f5c5ba6eb68ec5332b549b73f7f8d79feda9cbb49628
+dist/2025-04-02/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=670a6ce01ee6e5225b152a1357eba9a41cb47f04d08cdc8a0828eded4132aba1
+dist/2025-04-02/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=cf92bed8c784e9579c09305fd227df3992950c227bc844a9b09995828d62e2cc
+dist/2025-04-02/clippy-beta-i686-pc-windows-gnu.tar.gz=58238b6f4f8ad957a39c0eb63b45007d1c3f8c79e98307c7e5a531b7309a30f4
+dist/2025-04-02/clippy-beta-i686-pc-windows-gnu.tar.xz=e77c5215b3e96c59fa150330cb5144db66dac377fdad3be9c28f9fa07d9fb7cc
+dist/2025-04-02/clippy-beta-i686-pc-windows-msvc.tar.gz=7c65df8af1f6f4102ffbd7fdaec50c24f89f2631edd06642732f1b5c74558ab4
+dist/2025-04-02/clippy-beta-i686-pc-windows-msvc.tar.xz=eeb119d26e1e2ddd3ef72741158d75d0db254f6420fd729d34abe5d172c7d765
+dist/2025-04-02/clippy-beta-i686-unknown-linux-gnu.tar.gz=c43518b27adce17f06f89c70ab52ae4c94f1f7129a182c16f9bb28fbc8a5f40b
+dist/2025-04-02/clippy-beta-i686-unknown-linux-gnu.tar.xz=1d972c55d89cc01b7e408b4e24e8975bca29ff28578f224024a00f00d17c28b8
+dist/2025-04-02/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=0d779bd9fcc5ed8e1db81a3a385bc0158c3903e5b0f0e4c99d172eee106a4f3e
+dist/2025-04-02/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=5515e0678c081ddae45f3f0c3c7ae58cc2f7b1141e1557a39826bf1aa58a2480
+dist/2025-04-02/clippy-beta-loongarch64-unknown-linux-musl.tar.gz=e99599c1fd0cab2eb0e89dd8e37e90ee2106d602a3edb3473fd65768bb8f7b27
+dist/2025-04-02/clippy-beta-loongarch64-unknown-linux-musl.tar.xz=f346a801dee3734461eab4303469d31faaf3e8f0d733b854470722ed48c66276
+dist/2025-04-02/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=cd7b58e507d6695ada446ef9fa113a9588501832f4627b3e7cc0000a77c9265f
+dist/2025-04-02/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=0a7073874663b4ce8eb47a0257ac0cf8049acb34703241466f1208489c4dbee0
+dist/2025-04-02/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=78d0b9581a7d79549bbb6a7e8984bf923a7b80bf6bb3979a90e90ceed8e66d33
+dist/2025-04-02/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=79069a26ed617a2a07eef7cf098d028cb0c172fc4a6dc99115a51862b1b8bea8
+dist/2025-04-02/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=23c58421839105c88937ad90a92603b7fcd6d9e21f291ab8c419fce1663a20a5
+dist/2025-04-02/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=b546706d28c46f5bd3799d6b42201962ec2e9d6baf8df2b66cfcf1bc42789036
+dist/2025-04-02/clippy-beta-powerpc64le-unknown-linux-musl.tar.gz=31cf0d973eb3f0ca341a8d64c26b8b3b045b44b3c00d2497893dac6e44ebdeb4
+dist/2025-04-02/clippy-beta-powerpc64le-unknown-linux-musl.tar.xz=8afd89866c41631d4f4ac4d8a06d943473af7a96b043f6112216a04863817820
+dist/2025-04-02/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=f08bf4ed1519e7c47f354a0d0b750933342314bacd4be761746666cf455cf74b
+dist/2025-04-02/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=e502f83f811c35e43df0a5e158d9eb61f60c9e1aacc75b588b2ba85022ca4b3e
+dist/2025-04-02/clippy-beta-s390x-unknown-linux-gnu.tar.gz=21bede57083544028238ef6c9d24cbf9194a35c88500f2d0c5d50e6f0ae79616
+dist/2025-04-02/clippy-beta-s390x-unknown-linux-gnu.tar.xz=670c0a293e1b01f331c2645b648c1df087da4c1b5d689f608279b1ba524cbaef
+dist/2025-04-02/clippy-beta-x86_64-apple-darwin.tar.gz=a6552e032c047203d5a9f5b767945c7a556be35468c42631c0c84cd049e24a8a
+dist/2025-04-02/clippy-beta-x86_64-apple-darwin.tar.xz=17a9e9ea8e0d6140080b7fa4e3c77ad1a7fde3c3179f26b0aabe34c3af73b58a
+dist/2025-04-02/clippy-beta-x86_64-pc-windows-gnu.tar.gz=2ffa8663502f4c6bba049318c70e79c174fd717d45ab4427103fc11563be678f
+dist/2025-04-02/clippy-beta-x86_64-pc-windows-gnu.tar.xz=8c0a71f226b229f30a9acfbc1ab7c6bbedf692ef7b26737721a0518d3f1972ab
+dist/2025-04-02/clippy-beta-x86_64-pc-windows-msvc.tar.gz=463c7a5d2a11beaeb1e63bc769db89fb9996a0558da15b4e091befe982893711
+dist/2025-04-02/clippy-beta-x86_64-pc-windows-msvc.tar.xz=40241fa6e463df734096e0e910b414c83d8a4dc8706b7c712cc170844e59e3c6
+dist/2025-04-02/clippy-beta-x86_64-unknown-freebsd.tar.gz=6464044b05b326d8ea594a963e38a52a1e27e0f028704427c41ec5e93e3772d9
+dist/2025-04-02/clippy-beta-x86_64-unknown-freebsd.tar.xz=77cdeb1e838c3da1d01252481f7c06149b0b8e7df48c2a2ee5961f4550d7b662
+dist/2025-04-02/clippy-beta-x86_64-unknown-illumos.tar.gz=d51238e1ad2329b9309e94b40f3374788e2fda9bf47466841a841392835e8a5e
+dist/2025-04-02/clippy-beta-x86_64-unknown-illumos.tar.xz=6ad33945045790946fae843f63a805e60c09157e106ff342d3b99a201cd221e1
+dist/2025-04-02/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=64b4f85d9eb75172928b46540090128ce9eec00e275d9027f74d0d5d4106bd76
+dist/2025-04-02/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=b090383b4ebeae96fb340f0a363ee0276eb1f17a4f2a0f2ed81aff039f21bf78
+dist/2025-04-02/clippy-beta-x86_64-unknown-linux-musl.tar.gz=8d8025922c563bb1c872111722a4de298a8f85cd5be3e4cf753d44d6b8304de6
+dist/2025-04-02/clippy-beta-x86_64-unknown-linux-musl.tar.xz=ecf15ae9eb7dafe97afd69133f13364dac09d5e6edc35ddab91fb4ac32e17d42
+dist/2025-04-02/clippy-beta-x86_64-unknown-netbsd.tar.gz=c802af6a6f454b771046bd4a5207bdbe538cb6827becc9174dc229de5f874426
+dist/2025-04-02/clippy-beta-x86_64-unknown-netbsd.tar.xz=03d1e16eaf6f83f80e4cef8c7beebee97498135dd3138b97f97186b545edfb86
+dist/2025-04-02/rustfmt-nightly-aarch64-apple-darwin.tar.gz=c02047132bc7b48bbe930dfddb3afd31349eb042cb101a19d6e4360ea6e586ad
+dist/2025-04-02/rustfmt-nightly-aarch64-apple-darwin.tar.xz=cf825dfaeb4d97eb2819ff8e46360192f480960f6b516e328ef8a9493d413a9f
+dist/2025-04-02/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=588551cbfb62eb4ed4e5755fe6eb3e1499a79e24a8a75f448b10d9a2237c63db
+dist/2025-04-02/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=df666f179fcfccb316aeb1a5eb4c17710b23198176edb34ba8b98c88cb369098
+dist/2025-04-02/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=b06f4aefa01300ef1827a29c9fcd2e4da0c13f3aad92b4c929f6e8811d53ab71
+dist/2025-04-02/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=059a888b8db76f5a3054a9a78a131d79c49060deaf70b2e2f03a4fcab44ab536
+dist/2025-04-02/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=f0117a7be9eefe70fbd2f0d3fc05c51f3a97d069dc99500520a5d0973178fc6a
+dist/2025-04-02/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=f2fa87f1e814d0fb163146cf6a47d9375fec2c3778f76c33988acaa1665dacf7
+dist/2025-04-02/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=fa53d4a6fb2ee3e1607d825afcc05063c0fa0dda1a3ede9a57e1ccc72cece8c4
+dist/2025-04-02/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=3d785d982878f9bda4778cca0f9365947665849d5f7d2ee4794d8c28df3ab8c8
+dist/2025-04-02/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=affb343357cd4c677cdeaf3b24698f20cfa15062cb63257aaa9bca3bd7baeeae
+dist/2025-04-02/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=6eb95c2021571a0c1ad3e3edf58fa4daa7711a9085e2ab61bc75799252183358
+dist/2025-04-02/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=1dffc39afb9210c77e6d45b68cb801247f00afdf33107963c82a83bd94d2225e
+dist/2025-04-02/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=2da28dd8ec76744a7629619f527196689eb35e9bc60f3a5965ed69486e44235d
+dist/2025-04-02/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=5b1b39125106cdcbf12be9d5786900852f54eaa1429cabf28eeb68f96a008f90
+dist/2025-04-02/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=3f2ecb3787c82a8dae89929aca4f2f3af790f1ab3c698adf21dde21c919a4052
+dist/2025-04-02/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=eeb8b3f10f1cd75fac4e9e13dd1aee5941f38f1ff7fcfcaa69fcc3a42ea7c49a
+dist/2025-04-02/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=afd81cfd8d5fb37427c7eb2a1429c3b06d8daa1f42002c7230718fc56e132c47
+dist/2025-04-02/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=5eb0f065a5403645ebb6c01d7f27a763f9446b8a48db5b6ff962b6f7c0f3ea3b
+dist/2025-04-02/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=3576e2e8ecc563cfbc4b3f464d80f8e27f412b5eb267656dc5f0316a11a2d299
+dist/2025-04-02/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=5e69db53a1161ad7616f9e50d1a7fef785840bdf0ba81757d0b6811078692921
+dist/2025-04-02/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=ba9d18dd2d63bad1e2863c9e14bbc4bd282d03cb806d03011d2d61ce701d934f
+dist/2025-04-02/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=b112f8c2e6ec011382c02a40ca07f30e1885a1396a7f2c30f099e56d756f2f54
+dist/2025-04-02/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=42af68aa0b77306187d13ef881ee4327856f505a8a518f46244ffb17037f7e4e
+dist/2025-04-02/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=ed4277c9c8a27fdb97911bb9fbb46385b5fd807ac9338d31eecc3240bb0bc5c2
+dist/2025-04-02/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=4cf3a7a64edd09b5d8ad72af545c15013842072e70789d1741f845f27c60566d
+dist/2025-04-02/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=65d49556ac1abd1da9cb7c41e518f85213ee2b1f05559c917614937d4c0cada9
+dist/2025-04-02/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=535ea938d888ea12c139740e5d25ac4b82135b3274b8d86c3c59e36928922ec6
+dist/2025-04-02/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=9776e0c641ae8a229453fe1fbdaaae05ea0caf37bb4893a00fe86e5d63d1241a
+dist/2025-04-02/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=bf73cfd35802b2706d0db96c854e8a4c45398297a59aef92226ac28d8bb69417
+dist/2025-04-02/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.gz=307012d0741898b3a2840ba3535832943ab6127f27323e587e1918b2023b37a2
+dist/2025-04-02/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.xz=79912529a393cb77c604f5a16d5b22611e938971656efd57fc5ef1980ffad35a
+dist/2025-04-02/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=854280cb3eeac146196ba30c8f3a010d568bf5bf9613d1870bd052a2aa3a03c0
+dist/2025-04-02/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=36e6cfc2b333cf077e3e1bf651acab4e6845330fa151848926d7b33fafa016f3
+dist/2025-04-02/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=19409bf4daa2e4d76c99659d7348f9a7dd4eb640c8bc81d93dc9170a1e51b7ba
+dist/2025-04-02/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=999346ff469e15507ec43c0b265a94b98ee99a0096d68ea0307a2280d138838f
+dist/2025-04-02/rustfmt-nightly-x86_64-apple-darwin.tar.gz=6a52a943d59edb9e6ed97643b01a2ca2f51abb6fba1b4c9b73f59646372aac01
+dist/2025-04-02/rustfmt-nightly-x86_64-apple-darwin.tar.xz=3701a72b39a31e31c9fe65afa660a507088dfe6039867a2019bfb69970872bad
+dist/2025-04-02/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=c0dbe39a6dc72d96446312584055cfd75a4304c4859016ec7590d52813f0736c
+dist/2025-04-02/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=f9e8814cf2e0241bbe40bfafc62bb961d87060dd94c84fba8ea00b2992eafe2a
+dist/2025-04-02/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=b9a2c923b6794b3462882a9f5b1579e2463024a72ff34cdf4bdfd8b0f51ee528
+dist/2025-04-02/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=c5e8272c451a3d685842e07a996e8bdc305ccb02a02d39f7f4cc764be4b2adce
+dist/2025-04-02/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=d47cb1e290f09795a04652f33afba39f80f3b6dcc4b570c14c75b1d945c78f0a
+dist/2025-04-02/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=389ea9f755623dd3d887bbff71189f86d7397c82e2f8fe660c27784cf7c68a94
+dist/2025-04-02/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=b49f6c211c51a50309ddd2bcb4c886ebeef47e5413e6399778157bc90a37ed0e
+dist/2025-04-02/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=d53f55b6dba14bb2e2f90510c3e432781a8aad1f871d8f38795edf866ed4a4f3
+dist/2025-04-02/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=2b8d77937298b23522ab9bd2f64a829f6faf1dccb87033f6006aa8c324474b47
+dist/2025-04-02/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=0579d2a7c17cd585c49a42efe062466db777c1e7890f21b319234ee81c86ea39
+dist/2025-04-02/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=65bc50db8fbe283e876b9ae7d6c15ff0461c1db8b3327f2992a99d21bcc3266c
+dist/2025-04-02/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=120505da1a8cddfb3f549438a52b2c73c76a9f1c2f25709db13d61efd214d732
+dist/2025-04-02/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=d19004b3f6b9fa446e23f540b21a8f314d3bbcca11f753c9a6fdaf4c7ae7a2de
+dist/2025-04-02/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=e7facb66daed07789015c2d5b092afde5dbb1349d06cd0f80ae8319437587723
+dist/2025-04-02/rustc-nightly-aarch64-apple-darwin.tar.gz=3783e0aa4450a6bb913fc9a9799950892e65c7af9a2c895419090072999a2305
+dist/2025-04-02/rustc-nightly-aarch64-apple-darwin.tar.xz=4d3a72db4cfcd7663803f1a0b193326e37c7faecc0c97c3903a17fbc0f7c8848
+dist/2025-04-02/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=c253308683fd394b1287a4eb9ca00cb8557bd7f7f91af8b087adccf9153a94eb
+dist/2025-04-02/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=63c30a1e523266dd6f8d6bb1525484f51fc6462bd7946900e0590b219f2a8b47
+dist/2025-04-02/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=74d2313a732fc8401d62b9a8610bd9a25502f0372921c0e99d9d20f0cf8e3b19
+dist/2025-04-02/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=a96db92f8c7cebe6e0d140a1853ecaa038e04975d62f17950e141d8ac2452536
+dist/2025-04-02/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=250e2c21af9d4b284c7455668ebcc3d1e408c20cda1abf0ee69acac4c873e5ed
+dist/2025-04-02/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=931714cf51d93fee5cc9465e9a0e9d34c771fe2aaae46994f3b00da4c95a8f54
+dist/2025-04-02/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=28f993889175ba3feb78b458be5282b2564a7c9b96117fed071835ff7b47f43f
+dist/2025-04-02/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=8645d1a7510cc13e2cd9abeffa71cbfb5f3a99990d27da2b05c336801a51c7f0
+dist/2025-04-02/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=a86525223d8c5d67b0a92382b6ebce65761cdb83629e11bf29d625d688908d38
+dist/2025-04-02/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=06a57a2c6298bb6e477d1e04922c626142bf96b2072684aecbbbf876bb4296f1
+dist/2025-04-02/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=a7fb3babdc244ea1f025f3033d13088c50696db8d6db29efcc6a78474a06769e
+dist/2025-04-02/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=b130a7efa1c2bdfa5ef51237d5233ab6bd8feade7dc596d120b6501b4766a569
+dist/2025-04-02/rustc-nightly-i686-pc-windows-gnu.tar.gz=ebb4dda0d1ced3ec5aa14b1ef38227628db92a87f45b817d4ce41ff026a687ec
+dist/2025-04-02/rustc-nightly-i686-pc-windows-gnu.tar.xz=43a69c9382b20249495824c149ffb5b5dae2ff7407c0c431859bc3e1f1ca4a7c
+dist/2025-04-02/rustc-nightly-i686-pc-windows-msvc.tar.gz=bf3eb550e148e89e7ff17be5e72ad0462d57f3c452bfdc46b80a1812ec2fe457
+dist/2025-04-02/rustc-nightly-i686-pc-windows-msvc.tar.xz=b2dde774c1ef573c6a889c2d78bbb98f535f22be4b20896797be2f10781f0eb4
+dist/2025-04-02/rustc-nightly-i686-unknown-linux-gnu.tar.gz=96d130960b0dc1d8fa54f53d22a8fa8cf5aa35d0b213071404122e4e714feab0
+dist/2025-04-02/rustc-nightly-i686-unknown-linux-gnu.tar.xz=d743c6126151dd18624382a4228bf90af1239fc7fd97e763009b31666fb860fb
+dist/2025-04-02/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=090ec673f24758b8a4d0ce7b8c58fc6015585bd8392e37760283ffbe6045298c
+dist/2025-04-02/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=c71ad975a15c440890a7358b5459b7ca6b9d5e1842dd353071467c2a3f841605
+dist/2025-04-02/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=8806875cee039409632e8baf5433227af04bd07d015329d9512cc4f4879f687c
+dist/2025-04-02/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=cebc3a4f1eb71e86e4e63f78e1c2f86fc98f7d23db1a3cb7e4c4d385e5591d51
+dist/2025-04-02/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=643dc0fe347a78a82321b5f47b41b09025856b6383ef67274ba3324879aae75e
+dist/2025-04-02/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=955018b90daf3797497dfc423aec731e8d0320b96dcf42db1705b761e1e0dd58
+dist/2025-04-02/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=aed278e57ffe0eb54328a9536607bc179806e0c2de9fccb9779a4517752899e5
+dist/2025-04-02/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=0b6e0305b13d867c677243b16613f62b07352038f5e7ad7e1865cc2d00168283
+dist/2025-04-02/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=e10d8eee30be690aa2e6ff58ca554d47173086d5df8f0ea8581b3fd10d4cee0a
+dist/2025-04-02/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=3ca3c258404dd8718321ed8a50aa6512fea9d810120db225a3fcfe56d7b83064
+dist/2025-04-02/rustc-nightly-powerpc64le-unknown-linux-musl.tar.gz=ddfc329b8932ad796c0eb7618632f9ae0c5ffb7a6093ea7d5cc4185fc0537f22
+dist/2025-04-02/rustc-nightly-powerpc64le-unknown-linux-musl.tar.xz=b4e82b64f2e934e17fc9b270295554a8bf0bd3d38ffffc66b367aad5bee3ad6f
+dist/2025-04-02/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=116d290065bd9e8ff2ca57440e94f773f68adf79aedba767159dfb92fe1a42b0
+dist/2025-04-02/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=6e1deb0c47bba4b56bbf1d04344e45f0490938455aee421629f2fcfd309eff64
+dist/2025-04-02/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=445f8a0ca579153b449fa0d36460227af68399c4227be76e4cbb3d65cef9055c
+dist/2025-04-02/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=d87bcac173e9800dc1c1b28e668a1b4c3616029d0ca53adfa4ac382733610193
+dist/2025-04-02/rustc-nightly-x86_64-apple-darwin.tar.gz=4342b89aed19f409df56bfac3d6ac071a02cb6839a52d19fdff9d10cc1d9f540
+dist/2025-04-02/rustc-nightly-x86_64-apple-darwin.tar.xz=cb787327895f275e6f9025bb38c6337492c839310931b8c7ba39743813621701
+dist/2025-04-02/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=6cddd0d3cf18780b36776fd0324643a36b3294923531a741cc763516c8238caf
+dist/2025-04-02/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=cefc15752bd84b290f50b958b96feb0134d420a10c6f36791424c762cda08abc
+dist/2025-04-02/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=731e968787044081453a559a95579435654b47f91a9b7f94579ac007ed3e4cf9
+dist/2025-04-02/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=3d9b173043aed73aa3ab1fa0b14d0ce2149a4943f4bb10aa1e31af619afe0eed
+dist/2025-04-02/rustc-nightly-x86_64-unknown-freebsd.tar.gz=c0df2f0a354d2d657d8ec8091bc094060321b343c8e7bb8e4315cfe042dacfc3
+dist/2025-04-02/rustc-nightly-x86_64-unknown-freebsd.tar.xz=8933bc0361484ac7c6b226defaea73eda5c4e10462e7ea54052c7e1d370e48c0
+dist/2025-04-02/rustc-nightly-x86_64-unknown-illumos.tar.gz=5887f913ac80dfe9826619227c66eb234a2b4848e6bc4f41c6fdd8102bf981e9
+dist/2025-04-02/rustc-nightly-x86_64-unknown-illumos.tar.xz=4a54b8b09eba43df0d99fb6e03177cf8ba2214a5810be52ac33ee3d9d33e98bc
+dist/2025-04-02/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=1c0bb76acd7944804d52c3139f4dcf154d3221cdeb300bb6b9bca726cd6ad30f
+dist/2025-04-02/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=e67a33440c3e021ff2dd41add0fb05db6c0e8ae68bd30d33e8b3185b0bb7191b
+dist/2025-04-02/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=0ea7e17d7bb67d6a6c4b2f864aaffcd96512f15f17f0acc63751eb1df6c486a7
+dist/2025-04-02/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=b73d37b704ab58921172cc561f5598db6a504dcd4d7980966f7c26caaf6d3594
+dist/2025-04-02/rustc-nightly-x86_64-unknown-netbsd.tar.gz=986f6c594d37bcbd3833e053640ba8775f68d26a65c5618386654ef55d7b3542
+dist/2025-04-02/rustc-nightly-x86_64-unknown-netbsd.tar.xz=c0d9a88c30d2ab38ec3a11fabb5515ed9bc3ac1a8e35a438d68bf7ff82f6b843
diff --git a/src/tools/bump-stage0/src/main.rs b/src/tools/bump-stage0/src/main.rs
index f51072718a3..d679084ae44 100644
--- a/src/tools/bump-stage0/src/main.rs
+++ b/src/tools/bump-stage0/src/main.rs
@@ -65,32 +65,33 @@ impl Tool {
             nightly_branch,
         } = &self.config;
 
-        file_content.push_str(&format!("dist_server={}", dist_server));
-        file_content.push_str(&format!("\nartifacts_server={}", artifacts_server));
+        file_content.push_str(&format!("dist_server={}\n", dist_server));
+        file_content.push_str(&format!("artifacts_server={}\n", artifacts_server));
         file_content.push_str(&format!(
-            "\nartifacts_with_llvm_assertions_server={}",
+            "artifacts_with_llvm_assertions_server={}\n",
             artifacts_with_llvm_assertions_server
         ));
-        file_content.push_str(&format!("\ngit_merge_commit_email={}", git_merge_commit_email));
-        file_content.push_str(&format!("\ngit_repository={}", git_repository));
-        file_content.push_str(&format!("\nnightly_branch={}", nightly_branch));
+        file_content.push_str(&format!("git_merge_commit_email={}\n", git_merge_commit_email));
+        file_content.push_str(&format!("git_repository={}\n", git_repository));
+        file_content.push_str(&format!("nightly_branch={}\n", nightly_branch));
 
-        file_content.push_str("\n\n");
+        file_content.push_str("\n");
         file_content.push_str(COMMENTS);
+        file_content.push_str("\n");
 
         let compiler = self.detect_compiler()?;
-        file_content.push_str(&format!("\ncompiler_date={}", compiler.date));
-        file_content.push_str(&format!("\ncompiler_version={}", compiler.version));
+        file_content.push_str(&format!("compiler_date={}\n", compiler.date));
+        file_content.push_str(&format!("compiler_version={}\n", compiler.version));
 
         if let Some(rustfmt) = self.detect_rustfmt()? {
-            file_content.push_str(&format!("\nrustfmt_date={}", rustfmt.date));
-            file_content.push_str(&format!("\nrustfmt_version={}", rustfmt.version));
+            file_content.push_str(&format!("rustfmt_date={}\n", rustfmt.date));
+            file_content.push_str(&format!("rustfmt_version={}\n", rustfmt.version));
         }
 
         file_content.push_str("\n");
 
         for (key, value) in self.checksums {
-            file_content.push_str(&format!("\n{}={}", key, value));
+            file_content.push_str(&format!("{}={}\n", key, value));
         }
 
         std::fs::write(PATH, file_content)?;
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject a6c604d1b8a2f2a8ff1f3ba6092f9fda42f4b7e
+Subproject 864f74d4eadcaea3eeda37a2e7f4d34de233d51
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 94c170d73af..f5a8e3dc387 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -25,6 +25,7 @@ path = "src/driver.rs"
 [dependencies]
 clippy_config = { path = "clippy_config" }
 clippy_lints = { path = "clippy_lints" }
+clippy_utils = { path = "clippy_utils" }
 rustc_tools_util = { path = "rustc_tools_util", version = "0.4.2" }
 tempfile = { version = "3.3", optional = true }
 termize = "0.1"
diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
index ab34af7c317..e5439a6d401 100644
--- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs
+++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
@@ -111,8 +111,8 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones {
             // Only suggest if `clone_from`/`clone_into` is explicitly implemented
             && resolved_assoc_items.in_definition_order().any(|assoc|
                 match which_trait {
-                    CloneTrait::Clone => assoc.name == sym::clone_from,
-                    CloneTrait::ToOwned => assoc.name.as_str() == "clone_into",
+                    CloneTrait::Clone => assoc.name() == sym::clone_from,
+                    CloneTrait::ToOwned => assoc.name().as_str() == "clone_into",
                 }
             )
             && !clone_source_borrows_from_dest(cx, lhs, rhs.span)
diff --git a/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs b/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs
index cd38aed26a3..7fab97d3ea1 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs
@@ -1,10 +1,10 @@
 use super::{Attribute, DEPRECATED_CFG_ATTR, DEPRECATED_CLIPPY_CFG_ATTR, unnecessary_clippy_cfg};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, MsrvStack};
+use clippy_utils::sym;
 use rustc_ast::AttrStyle;
 use rustc_errors::Applicability;
 use rustc_lint::EarlyContext;
-use rustc_span::sym;
 
 pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &MsrvStack) {
     // check cfg_attr
@@ -18,7 +18,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &MsrvStack) {
             && msrv.meets(msrvs::TOOL_ATTRIBUTES)
             // check for `rustfmt_skip` and `rustfmt::skip`
             && let Some(skip_item) = &items[1].meta_item()
-            && (skip_item.has_name(sym!(rustfmt_skip))
+            && (skip_item.has_name(sym::rustfmt_skip)
                 || skip_item
                     .path
                     .segments
diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
index e3e081ce08e..1cb43ab02a3 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
@@ -2,10 +2,10 @@ use super::USELESS_ATTRIBUTE;
 use super::utils::{is_lint_level, is_word, namespace_and_lint};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{SpanRangeExt, first_line_of_span};
+use clippy_utils::sym;
 use rustc_ast::{Attribute, Item, ItemKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, LintContext};
-use rustc_span::sym;
 
 pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) {
     let skip_unused_imports = attrs.iter().any(|attr| attr.has_name(sym::macro_use));
@@ -61,7 +61,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) {
                             if is_word(lint, sym::unused_imports) && skip_unused_imports {
                                 return;
                             }
-                            if is_word(lint, sym!(unused_extern_crates)) {
+                            if is_word(lint, sym::unused_extern_crates) {
                                 return;
                             }
                         },
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 adac2f27ea8..4a876b85416 100644
--- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
@@ -53,10 +53,10 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -
         .not_trait()
         .filter(|trait_id| implements_trait(cx, ty, *trait_id, &[]))
         .and_then(|trait_id| {
-            cx.tcx.associated_items(trait_id).find_by_name_and_kind(
+            cx.tcx.associated_items(trait_id).find_by_ident_and_kind(
                 cx.tcx,
                 Ident::from_str("Output"),
-                ty::AssocKind::Type,
+                ty::AssocTag::Type,
                 trait_id,
             )
         })
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index 48b5d4da888..7bb5dbee126 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -199,7 +199,7 @@ fn check_simplify_not(cx: &LateContext<'_>, msrv: Msrv, expr: &Expr<'_>) {
         && !expr.span.from_expansion()
         && !inner.span.from_expansion()
         && let Some(suggestion) = simplify_not(cx, msrv, inner)
-        && cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, expr.hir_id).0 != Level::Allow
+        && cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, expr.hir_id).level != Level::Allow
     {
         use clippy_utils::sugg::{Sugg, has_enclosing_paren};
         let maybe_par = if let Some(sug) = Sugg::hir_opt(cx, inner) {
@@ -605,7 +605,7 @@ impl<'tcx> NonminimalBoolVisitor<'_, 'tcx> {
                 }
             }
             let nonminimal_bool_lint = |mut suggestions: Vec<_>| {
-                if self.cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, e.hir_id).0 != Level::Allow {
+                if self.cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, e.hir_id).level != Level::Allow {
                     suggestions.sort();
                     span_lint_hir_and_then(
                         self.cx,
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
index 53c24a3faf1..d1a8590c59b 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
@@ -69,7 +69,7 @@ impl EarlyLintPass for DisallowedScriptIdents {
         // Implementation is heavily inspired by the implementation of [`non_ascii_idents`] lint:
         // https://github.com/rust-lang/rust/blob/master/compiler/rustc_lint/src/non_ascii_idents.rs
 
-        let check_disallowed_script_idents = cx.builder.lint_level(DISALLOWED_SCRIPT_IDENTS).0 != Level::Allow;
+        let check_disallowed_script_idents = cx.builder.lint_level(DISALLOWED_SCRIPT_IDENTS).level != Level::Allow;
         if !check_disallowed_script_idents {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs
index f6c10da1596..bf549dcdb50 100644
--- a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs
@@ -38,7 +38,7 @@ pub fn check(
     // of all `#[test]` attributes in not ignored code examples
     fn check_code_sample(code: String, edition: Edition, ignore: bool) -> (bool, Vec<Range<usize>>) {
         rustc_driver::catch_fatal_errors(|| {
-            rustc_span::create_session_globals_then(edition, None, || {
+            rustc_span::create_session_globals_then(edition, &[], None, || {
                 let mut test_attr_spans = vec![];
                 let filename = FileName::anon_source_code(&code);
 
diff --git a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs
index 243c99a19ce..ce551a64d99 100644
--- a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs
+++ b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs
@@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
 use rustc_ast::ast::{Crate, Inline, Item, ItemKind, ModKind};
 use rustc_errors::MultiSpan;
 use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext};
+use rustc_middle::lint::LevelAndSource;
 use rustc_session::impl_lint_pass;
 use rustc_span::{FileName, Span};
 use std::collections::BTreeMap;
@@ -45,11 +46,10 @@ declare_clippy_lint! {
     "file loaded as module multiple times"
 }
 
-#[derive(PartialOrd, Ord, PartialEq, Eq)]
 struct Modules {
     local_path: PathBuf,
     spans: Vec<Span>,
-    lint_levels: Vec<Level>,
+    lint_levels: Vec<LevelAndSource>,
 }
 
 #[derive(Default)]
@@ -95,11 +95,11 @@ impl EarlyLintPass for DuplicateMod {
                 .iter()
                 .zip(lint_levels)
                 .filter_map(|(span, lvl)| {
-                    if let Some(id) = lvl.get_expectation_id() {
+                    if let Some(id) = lvl.lint_id {
                         cx.fulfill_expectation(id);
                     }
 
-                    (!matches!(lvl, Level::Allow | Level::Expect(_))).then_some(*span)
+                    (!matches!(lvl.level, Level::Allow | Level::Expect)).then_some(*span)
                 })
                 .collect();
 
diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
index cd9ab2764ac..3afb687040f 100644
--- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
+++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
@@ -45,6 +45,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
         pats.iter().all(unary_pattern)
     }
     match &pat.kind {
+        PatKind::Missing => unreachable!(),
         PatKind::Slice(_, _, _)
         | PatKind::Range(_, _, _)
         | PatKind::Binding(..)
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index 3862ff7921d..06224f57c5c 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -550,7 +550,7 @@ impl<'tcx> FormatArgsExpr<'_, 'tcx> {
         // a `Target` that is in `self.ty_msrv_map`.
         if let Some(deref_trait_id) = self.cx.tcx.lang_items().deref_trait()
             && implements_trait(self.cx, ty, deref_trait_id, &[])
-            && let Some(target_ty) = self.cx.get_associated_type(ty, deref_trait_id, "Target")
+            && let Some(target_ty) = self.cx.get_associated_type(ty, deref_trait_id, sym::Target)
             && let Some(msrv) = self.ty_msrv_map.get(&target_ty)
             && msrv.is_none_or(|msrv| self.msrv.meets(self.cx, msrv))
         {
diff --git a/src/tools/clippy/clippy_lints/src/format_push_string.rs b/src/tools/clippy/clippy_lints/src/format_push_string.rs
index 68cc50f3939..b64d608c0c7 100644
--- a/src/tools/clippy/clippy_lints/src/format_push_string.rs
+++ b/src/tools/clippy/clippy_lints/src/format_push_string.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher;
 use clippy_utils::ty::is_type_lang_item;
-use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem, MatchSource};
+use rustc_hir::{AssignOpKind, Expr, ExprKind, LangItem, MatchSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
@@ -77,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatPushString {
                     return;
                 }
             },
-            ExprKind::AssignOp(op, left, arg) if op.node == BinOpKind::Add && is_string(cx, left) => arg,
+            ExprKind::AssignOp(op, left, arg) if op.node == AssignOpKind::AddAssign && is_string(cx, left) => arg,
             _ => return,
         };
         if is_format(cx, arg) {
diff --git a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs
index 041f6228fba..4495aeb5953 100644
--- a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs
@@ -22,8 +22,8 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &ImplItem<'_>, ignored
         && let Some(did) = trait_item_def_id_of_impl(items, item.owner_id)
         && !is_from_ignored_trait(trait_ref, ignored_traits)
     {
-        let mut param_idents_iter = cx.tcx.hir_body_param_names(body_id);
-        let mut default_param_idents_iter = cx.tcx.fn_arg_names(did).iter().copied();
+        let mut param_idents_iter = cx.tcx.hir_body_param_idents(body_id);
+        let mut default_param_idents_iter = cx.tcx.fn_arg_idents(did).iter().copied();
 
         let renames = RenamedFnArgs::new(&mut default_param_idents_iter, &mut param_idents_iter);
         if !renames.0.is_empty() {
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
index 41d2b18803d..185fc2aa2d4 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
@@ -5,7 +5,7 @@ use clippy_utils::source::snippet_with_context;
 use rustc_ast::ast::{LitIntType, LitKind};
 use rustc_data_structures::packed::Pu128;
 use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Stmt, StmtKind};
+use rustc_hir::{AssignOpKind, BinOpKind, Block, Expr, ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{IntTy, Ty, UintTy};
 use rustc_session::declare_lint_pass;
@@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd {
             && ex.span.ctxt() == ctxt
             && expr1.span.ctxt() == ctxt
             && clippy_utils::SpanlessEq::new(cx).eq_expr(l, target)
-            && BinOpKind::Add == op1.node
+            && AssignOpKind::AddAssign == op1.node
             && let ExprKind::Lit(lit) = value.kind
             && let LitKind::Int(Pu128(1), LitIntType::Unsuffixed) = lit.node
             && block.expr.is_none()
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
index cbc3e2ccd5b..5d7d3ae3f24 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
@@ -8,7 +8,7 @@ use clippy_utils::{
 use rustc_ast::ast::LitKind;
 use rustc_data_structures::packed::Pu128;
 use rustc_errors::Applicability;
-use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath};
+use rustc_hir::{AssignOpKind, BinOp, BinOpKind, Expr, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
@@ -366,7 +366,7 @@ fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a Exp
     match peel_blocks_with_stmt(expr).kind {
         ExprKind::AssignOp(ref op1, target, value) => {
             // Check if literal being subtracted is one
-            (BinOpKind::Sub == op1.node && is_integer_literal(value, 1)).then_some(target)
+            (AssignOpKind::SubAssign == op1.node && is_integer_literal(value, 1)).then_some(target)
         },
         ExprKind::Assign(target, value, _) => {
             if let ExprKind::Binary(ref op1, left1, right1) = value.kind
diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
index d02d9b2102b..430f2411183 100644
--- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
@@ -315,7 +315,7 @@ fn check<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds<'tcx>) {
                 assocs
                     .filter_by_name_unhygienic(constraint.ident.name)
                     .next()
-                    .is_some_and(|assoc| assoc.kind == ty::AssocKind::Type)
+                    .is_some_and(|assoc| assoc.is_type())
                 })
         {
             emit_lint(cx, poly_trait, bounds, index, implied_constraints, bound);
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 72e22ae59d8..77085d52a32 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -13,7 +13,7 @@ use rustc_hir::{
     QPath, TraitItemRef, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
+use rustc_middle::ty::{self, FnSig, Ty};
 use rustc_session::declare_lint_pass;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::sym;
@@ -288,8 +288,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, ident: Iden
             .items()
             .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(is_empty))
             .any(|i| {
-                i.kind == AssocKind::Fn
-                    && i.fn_has_self_parameter
+                i.is_method()
                     && cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1
             });
 
@@ -466,7 +465,7 @@ fn check_for_is_empty(
         .inherent_impls(impl_ty)
         .iter()
         .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(is_empty))
-        .find(|item| item.kind == AssocKind::Fn);
+        .find(|item| item.is_fn());
 
     let (msg, is_empty_span, self_kind) = match is_empty {
         None => (
@@ -486,7 +485,7 @@ fn check_for_is_empty(
             None,
         ),
         Some(is_empty)
-            if !(is_empty.fn_has_self_parameter
+            if !(is_empty.is_method()
                 && check_is_empty_sig(
                     cx,
                     cx.tcx.fn_sig(is_empty.def_id).instantiate_identity().skip_binder(),
@@ -608,7 +607,7 @@ fn is_empty_array(expr: &Expr<'_>) -> bool {
 fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     /// Gets an `AssocItem` and return true if it matches `is_empty(self)`.
     fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool {
-        if item.kind == AssocKind::Fn {
+        if item.is_fn() {
             let sig = cx.tcx.fn_sig(item.def_id).skip_binder();
             let ty = sig.skip_binder();
             ty.inputs().len() == 1
@@ -644,7 +643,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
                         && cx.tcx.get_diagnostic_item(sym::Deref).is_some_and(|deref_id| {
                             implements_trait(cx, ty, deref_id, &[])
                                 && cx
-                                    .get_associated_type(ty, deref_id, "Target")
+                                    .get_associated_type(ty, deref_id, sym::Target)
                                     .is_some_and(|deref_ty| ty_has_is_empty(cx, deref_ty, depth + 1))
                         }))
             },
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index cc3d972f017..3fe3cd67e16 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -408,9 +408,9 @@ mod zombie_processes;
 
 use clippy_config::{Conf, get_configuration_metadata, sanitize_explanation};
 use clippy_utils::macros::FormatArgsStorage;
-use utils::attr_collector::{AttrCollector, AttrStorage};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_lint::{Lint, LintId};
+use utils::attr_collector::{AttrCollector, AttrStorage};
 
 /// Register all pre expansion lints
 ///
diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs
index a5185d38e7c..3c6fbef2bda 100644
--- a/src/tools/clippy/clippy_lints/src/loops/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs
@@ -3,7 +3,9 @@ use clippy_utils::{get_parent_expr, is_integer_const, path_to_local, path_to_loc
 use rustc_ast::ast::{LitIntType, LitKind};
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{Visitor, walk_expr, walk_local};
-use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, LetStmt, Mutability, PatKind};
+use rustc_hir::{
+    AssignOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, LetStmt, Mutability, PatKind
+};
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, Ty};
@@ -58,7 +60,7 @@ impl<'tcx> Visitor<'tcx> for IncrementVisitor<'_, 'tcx> {
                 match parent.kind {
                     ExprKind::AssignOp(op, lhs, rhs) => {
                         if lhs.hir_id == expr.hir_id {
-                            *state = if op.node == BinOpKind::Add
+                            *state = if op.node == AssignOpKind::AddAssign
                                 && is_integer_const(self.cx, rhs, 1)
                                 && *state == IncrementVisitorVarState::Initial
                                 && self.depth == 0
diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs
index b712b351d06..98ad1f6a160 100644
--- a/src/tools/clippy/clippy_lints/src/macro_use.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_use.rs
@@ -153,9 +153,15 @@ impl LateLintPass<'_> for MacroUseImports {
                     [] | [_] => return,
                     [root, item] => {
                         if !check_dup.contains(&(*item).to_string()) {
-                            used.entry(((*root).to_string(), span, hir_id))
-                                .or_insert_with(Vec::new)
-                                .push((*item).to_string());
+                            used.entry((
+                                (*root).to_string(),
+                                span,
+                                hir_id.local_id,
+                                cx.tcx.def_path_hash(hir_id.owner.def_id.into()),
+                            ))
+                            .or_insert_with(|| (vec![], hir_id))
+                            .0
+                            .push((*item).to_string());
                             check_dup.push((*item).to_string());
                         }
                     },
@@ -171,15 +177,27 @@ impl LateLintPass<'_> for MacroUseImports {
                                     }
                                 })
                                 .collect::<Vec<_>>();
-                            used.entry(((*root).to_string(), span, hir_id))
-                                .or_insert_with(Vec::new)
-                                .push(filtered.join("::"));
+                            used.entry((
+                                (*root).to_string(),
+                                span,
+                                hir_id.local_id,
+                                cx.tcx.def_path_hash(hir_id.owner.def_id.into()),
+                            ))
+                            .or_insert_with(|| (vec![], hir_id))
+                            .0
+                            .push(filtered.join("::"));
                             check_dup.extend(filtered);
                         } else {
                             let rest = rest.to_vec();
-                            used.entry(((*root).to_string(), span, hir_id))
-                                .or_insert_with(Vec::new)
-                                .push(rest.join("::"));
+                            used.entry((
+                                (*root).to_string(),
+                                span,
+                                hir_id.local_id,
+                                cx.tcx.def_path_hash(hir_id.owner.def_id.into()),
+                            ))
+                            .or_insert_with(|| (vec![], hir_id))
+                            .0
+                            .push(rest.join("::"));
                             check_dup.extend(rest.iter().map(ToString::to_string));
                         }
                     },
@@ -190,7 +208,7 @@ impl LateLintPass<'_> for MacroUseImports {
         // If mac_refs is not empty we have encountered an import we could not handle
         // such as `std::prelude::v1::foo` or some other macro that expands to an import.
         if self.mac_refs.is_empty() {
-            for ((root, span, hir_id), path) in used {
+            for ((root, span, ..), (path, hir_id)) in used {
                 let import = if let [single] = &path[..] {
                     format!("{root}::{single}")
                 } else {
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 250f17fa902..a21597ffb93 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
@@ -253,6 +253,7 @@ fn iter_matching_struct_fields<'a>(
 impl<'a> NormalizedPat<'a> {
     fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) -> Self {
         match pat.kind {
+            PatKind::Missing => unreachable!(),
             PatKind::Wild | PatKind::Binding(.., None) => Self::Wild,
             PatKind::Binding(.., Some(pat))
             | PatKind::Box(pat)
diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
index 56fbd626eef..836c46240ce 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -406,6 +406,7 @@ impl<'a> PatState<'a> {
                 pats.iter().map(|p| p.pat),
             ),
 
+            PatKind::Missing => unreachable!(),
             PatKind::Wild
             | PatKind::Binding(_, _, _, None)
             | PatKind::Expr(_)
diff --git a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs
index e82211bbf3e..b5adc69e9a7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs
@@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Exp
         && let Ok(Some(fn_def)) = Instance::try_resolve(cx.tcx, cx.typing_env(), id, args)
         // find the provided definition of Iterator::last
         && let Some(item) = cx.tcx.get_diagnostic_item(sym::Iterator)
-        && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name.as_str() == "last")
+        && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name().as_str() == "last")
         // if the resolved method is the same as the provided definition
         && fn_def.def_id() == last_def.def_id
     {
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
index f51bdc78f8a..7bb625222ec 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
@@ -48,7 +48,7 @@ pub(super) fn check<'tcx>(
         && let Some(method_id) = typeck.type_dependent_def_id(cloned_call.hir_id)
         && cx.tcx.trait_of_item(method_id) == Some(iter_id)
         && let cloned_recv_ty = typeck.expr_ty_adjusted(cloned_recv)
-        && let Some(iter_assoc_ty) = cx.get_associated_type(cloned_recv_ty, iter_id, "Item")
+        && let Some(iter_assoc_ty) = cx.get_associated_type(cloned_recv_ty, iter_id, sym::Item)
         && matches!(*iter_assoc_ty.kind(), ty::Ref(_, ty, _) if !is_copy(cx, ty))
     {
         if needs_into_iter
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index 56ff7e2c61b..e4a29b6560e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -17,7 +17,7 @@ use rustc_hir::{
 };
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::{self, AssocKind, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty};
+use rustc_middle::ty::{self, AssocTag, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty};
 use rustc_span::symbol::Ident;
 use rustc_span::{Span, sym};
 
@@ -238,10 +238,10 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) -
             .instantiate_bound_regions_with_erased(sig.rebind(search_ty))
             .kind()
         && let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator)
-        && let Some(iter_item) = cx.tcx.associated_items(iter_trait).find_by_name_and_kind(
+        && let Some(iter_item) = cx.tcx.associated_items(iter_trait).find_by_ident_and_kind(
             cx.tcx,
             Ident::with_dummy_span(sym::Item),
-            AssocKind::Type,
+            AssocTag::Type,
             iter_trait,
         )
         && let args = cx.tcx.mk_args(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))])
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index c03420a5143..6eeeea5d77c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -78,7 +78,7 @@ pub(super) fn check<'tcx>(
                 .iter()
                 .flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg))
                 .find_map(|assoc| {
-                    if assoc.fn_has_self_parameter
+                    if assoc.is_method()
                         && cx.tcx.fn_sig(assoc.def_id).skip_binder().inputs().skip_binder().len() == 1
                     {
                         Some(assoc.def_id)
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
index c0e01568588..20cf35363d1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
@@ -99,7 +99,7 @@ pub fn check_for_loop_iter(
             && let Some(into_iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
             && let collection_ty = cx.typeck_results().expr_ty(collection)
             && implements_trait(cx, collection_ty, into_iterator_trait_id, &[])
-            && let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, "Item")
+            && let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, sym::Item)
             && iter_item_ty == into_iter_item_ty
             && let Some(collection_snippet) = collection.span.get_source_text(cx)
         {
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 62ba3012643..206b0a8ae3c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -153,7 +153,7 @@ fn check_addr_of_expr(
         }
         if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
             && implements_trait(cx, receiver_ty, deref_trait_id, &[])
-            && cx.get_associated_type(receiver_ty, deref_trait_id, "Target") == Some(target_ty)
+            && cx.get_associated_type(receiver_ty, deref_trait_id, sym::Target) == Some(target_ty)
             // Make sure that it's actually calling the right `.to_string()`, (#10033)
             // *or* this is a `Cow::into_owned()` call (which would be the wrong into_owned receiver (str != Cow)
             // but that's ok for Cow::into_owned specifically)
@@ -322,7 +322,7 @@ fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symb
         // add `.as_ref()` to the suggestion.
         let as_ref = if is_type_lang_item(cx, cx.typeck_results().expr_ty(expr), LangItem::String)
             && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
-            && cx.get_associated_type(cx.typeck_results().expr_ty(receiver), deref_trait_id, "Target")
+            && cx.get_associated_type(cx.typeck_results().expr_ty(receiver), deref_trait_id, sym::Target)
                 != Some(cx.tcx.types.str_)
         {
             ".as_ref()"
@@ -648,7 +648,7 @@ fn is_to_string_on_string_like<'a>(
         && let GenericArgKind::Type(ty) = generic_arg.unpack()
         && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
         && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef)
-        && (cx.get_associated_type(ty, deref_trait_id, "Target") == Some(cx.tcx.types.str_)
+        && (cx.get_associated_type(ty, deref_trait_id, sym::Target) == Some(cx.tcx.types.str_)
             || implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()]))
     {
         true
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 d78299fe08b..cdd6f4e5b03 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
@@ -10,7 +10,7 @@ use rustc_ast::{LitKind, RangeLimits};
 use rustc_data_structures::packed::Pu128;
 use rustc_data_structures::unhash::UnindexMap;
 use rustc_errors::{Applicability, Diag};
-use rustc_hir::{BinOp, Block, Body, Expr, ExprKind, UnOp};
+use rustc_hir::{BinOpKind, Block, Body, Expr, ExprKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::source_map::Spanned;
@@ -97,7 +97,7 @@ enum LengthComparison {
 ///
 /// E.g. for `v.len() > 5` this returns `Some((LengthComparison::IntLessThanLength, 5, v.len()))`
 fn len_comparison<'hir>(
-    bin_op: BinOp,
+    bin_op: BinOpKind,
     left: &'hir Expr<'hir>,
     right: &'hir Expr<'hir>,
 ) -> Option<(LengthComparison, usize, &'hir Expr<'hir>)> {
@@ -112,7 +112,7 @@ fn len_comparison<'hir>(
 
     // normalize comparison, `v.len() > 4` becomes `4 < v.len()`
     // this simplifies the logic a bit
-    let (op, left, right) = normalize_comparison(bin_op.node, left, right)?;
+    let (op, left, right) = normalize_comparison(bin_op, left, right)?;
     match (op, left.kind, right.kind) {
         (Rel::Lt, int_lit_pat!(left), _) => Some((LengthComparison::IntLessThanLength, left as usize, right)),
         (Rel::Lt, _, int_lit_pat!(right)) => Some((LengthComparison::LengthLessThanInt, right as usize, left)),
@@ -138,7 +138,7 @@ fn assert_len_expr<'hir>(
         && let ExprKind::Unary(UnOp::Not, condition) = &cond.kind
         && let ExprKind::Binary(bin_op, left, right) = &condition.kind
 
-        && let Some((cmp, asserted_len, slice_len)) = len_comparison(*bin_op, left, right)
+        && let Some((cmp, asserted_len, slice_len)) = len_comparison(bin_op.node, left, right)
         && let ExprKind::MethodCall(method, recv, [], _) = &slice_len.kind
         && cx.typeck_results().expr_ty_adjusted(recv).peel_refs().is_slice()
         && method.ident.name == sym::len
diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
index 7ee746365d1..e266c36b6e7 100644
--- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
@@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods {
                     cx,
                     MISSING_TRAIT_METHODS,
                     cx.tcx.def_span(item.owner_id),
-                    format!("missing trait method provided by default: `{}`", assoc.name),
+                    format!("missing trait method provided by default: `{}`", assoc.name()),
                     |diag| {
                         diag.span_help(cx.tcx.def_span(assoc.def_id), "implement the method");
                     },
diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
index be728e6c8b7..fbd287f5285 100644
--- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
+++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -261,10 +261,11 @@ fn check_expr<'tcx>(vis: &mut ReadVisitor<'_, 'tcx>, expr: &'tcx Expr<'_>) -> St
         | ExprKind::Assign(..)
         | ExprKind::Index(..)
         | ExprKind::Repeat(_, _)
-        | ExprKind::Struct(_, _, _) => {
+        | ExprKind::Struct(_, _, _)
+        | ExprKind::AssignOp(_, _, _) => {
             walk_expr(vis, expr);
         },
-        ExprKind::Binary(op, _, _) | ExprKind::AssignOp(op, _, _) => {
+        ExprKind::Binary(op, _, _) => {
             if op.node == BinOpKind::And || op.node == BinOpKind::Or {
                 // x && y and x || y always evaluate x first, so these are
                 // strictly sequenced.
diff --git a/src/tools/clippy/clippy_lints/src/module_style.rs b/src/tools/clippy/clippy_lints/src/module_style.rs
index 676d608eb31..7287193326f 100644
--- a/src/tools/clippy/clippy_lints/src/module_style.rs
+++ b/src/tools/clippy/clippy_lints/src/module_style.rs
@@ -73,8 +73,8 @@ impl_lint_pass!(ModStyle => [MOD_MODULE_FILES, SELF_NAMED_MODULE_FILES]);
 
 impl EarlyLintPass for ModStyle {
     fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
-        if cx.builder.lint_level(MOD_MODULE_FILES).0 == Level::Allow
-            && cx.builder.lint_level(SELF_NAMED_MODULE_FILES).0 == Level::Allow
+        if cx.builder.lint_level(MOD_MODULE_FILES).level == Level::Allow
+            && cx.builder.lint_level(SELF_NAMED_MODULE_FILES).level == Level::Allow
         {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
index f686cc912dd..e579dd5947d 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
@@ -299,7 +299,7 @@ fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool {
         .associated_items(trait_def_id)
         .in_definition_order()
         .any(|assoc_item| {
-            if assoc_item.fn_has_self_parameter {
+            if assoc_item.is_method() {
                 let self_ty = cx
                     .tcx
                     .fn_sig(assoc_item.def_id)
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index 08fcd17e555..a78a342d4fe 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -335,9 +335,12 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
             return;
         }
         match &expr.kind {
-            hir::ExprKind::AssignOp(op, lhs, rhs) | hir::ExprKind::Binary(op, lhs, rhs) => {
+            hir::ExprKind::Binary(op, lhs, rhs) => {
                 self.manage_bin_ops(cx, expr, op.node, lhs, rhs);
             },
+            hir::ExprKind::AssignOp(op, lhs, rhs) => {
+                self.manage_bin_ops(cx, expr, op.node.into(), lhs, rhs);
+            },
             hir::ExprKind::MethodCall(ps, receiver, args, _) => {
                 self.manage_method_call(args, cx, expr, ps, receiver);
             },
diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs
index f758d08d366..d32c062cf56 100644
--- a/src/tools/clippy/clippy_lints/src/operators/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs
@@ -913,9 +913,10 @@ impl<'tcx> LateLintPass<'tcx> for Operators {
                 );
             },
             ExprKind::AssignOp(op, lhs, rhs) => {
-                self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs);
-                misrefactored_assign_op::check(cx, e, op.node, lhs, rhs);
-                modulo_arithmetic::check(cx, e, op.node, lhs, rhs, false);
+                let bin_op = op.node.into();
+                self.arithmetic_context.check_binary(cx, e, bin_op, lhs, rhs);
+                misrefactored_assign_op::check(cx, e, bin_op, lhs, rhs);
+                modulo_arithmetic::check(cx, e, bin_op, lhs, rhs, false);
             },
             ExprKind::Assign(lhs, rhs, _) => {
                 assign_op_pattern::check(cx, e, lhs, rhs);
diff --git a/src/tools/clippy/clippy_lints/src/raw_strings.rs b/src/tools/clippy/clippy_lints/src/raw_strings.rs
index c6e6e782f9d..6a79cae32a5 100644
--- a/src/tools/clippy/clippy_lints/src/raw_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/raw_strings.rs
@@ -138,7 +138,7 @@ impl RawStrings {
                     );
                 },
             );
-            if !matches!(cx.get_lint_level(NEEDLESS_RAW_STRINGS), rustc_lint::Allow) {
+            if !matches!(cx.get_lint_level(NEEDLESS_RAW_STRINGS).level, rustc_lint::Allow) {
                 return;
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index 4cb73df8b48..d8e8ead2912 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -404,7 +404,7 @@ fn check_final_expr<'tcx>(
             match cx.tcx.hir_attrs(expr.hir_id) {
                 [] => {},
                 [attr] => {
-                    if matches!(Level::from_attr(attr), Some(Level::Expect(_)))
+                    if matches!(Level::from_attr(attr), Some((Level::Expect, _)))
                         && let metas = attr.meta_item_list()
                         && let Some(lst) = metas
                         && let [MetaItemInner::MetaItem(meta_item), ..] = lst.as_slice()
diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs
index 552135b15fd..33815cc3bac 100644
--- a/src/tools/clippy/clippy_lints/src/same_name_method.rs
+++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs
@@ -3,7 +3,6 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{HirId, Impl, ItemKind, Node, Path, QPath, TraitRef, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::AssocKind;
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
 use rustc_span::symbol::Symbol;
@@ -85,8 +84,8 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
                             cx.tcx
                                 .associated_items(did)
                                 .in_definition_order()
-                                .filter(|assoc_item| matches!(assoc_item.kind, AssocKind::Fn))
-                                .map(|assoc_item| assoc_item.name)
+                                .filter(|assoc_item| assoc_item.is_fn())
+                                .map(|assoc_item| assoc_item.name())
                                 .collect()
                         } else {
                             BTreeSet::new()
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
index fb426e91bf0..56bd8fefdb4 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
@@ -5,6 +5,7 @@ use core::ops::ControlFlow;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
+use rustc_span::Span;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -56,8 +57,27 @@ declare_lint_pass!(SuspiciousImpl => [SUSPICIOUS_ARITHMETIC_IMPL, SUSPICIOUS_OP_
 
 impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        if let hir::ExprKind::Binary(binop, _, _) | hir::ExprKind::AssignOp(binop, ..) = expr.kind
-            && let Some((binop_trait_lang, op_assign_trait_lang)) = binop_traits(binop.node)
+        match expr.kind {
+            hir::ExprKind::Binary(op, _, _) => {
+                self.check_expr_inner(cx, expr, op.node, op.span);
+            }
+            hir::ExprKind::AssignOp(op, _, _) => {
+                self.check_expr_inner(cx, expr, op.node.into(), op.span);
+            }
+            _ => {}
+        }
+    }
+}
+
+impl<'tcx> SuspiciousImpl {
+    fn check_expr_inner(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        expr: &'tcx hir::Expr<'_>,
+        binop: hir::BinOpKind,
+        span: Span,
+    ) {
+        if let Some((binop_trait_lang, op_assign_trait_lang)) = binop_traits(binop)
             && let Some(binop_trait_id) = cx.tcx.lang_items().get(binop_trait_lang)
             && let Some(op_assign_trait_id) = cx.tcx.lang_items().get(op_assign_trait_lang)
 
@@ -82,10 +102,10 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl {
             span_lint(
                 cx,
                 lint,
-                binop.span,
+                span,
                 format!(
                     "suspicious use of `{}` in `{}` impl",
-                    binop.node.as_str(),
+                    binop.as_str(),
                     cx.tcx.item_name(trait_id)
                 ),
             );
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index 7176d533b61..0337b74b4b1 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -10,7 +10,7 @@ use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir::intravisit::{Visitor, walk_expr};
 
 use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Block, Expr, ExprKind, LetStmt, PatKind, QPath, Stmt, StmtKind};
+use rustc_hir::{AssignOpKind, Block, Expr, ExprKind, LetStmt, PatKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
@@ -307,7 +307,7 @@ fn extract_sides_of_xor_assign<'a, 'hir>(
     if let StmtKind::Semi(expr) = stmt.kind
         && let ExprKind::AssignOp(
             Spanned {
-                node: BinOpKind::BitXor,
+                node: AssignOpKind::BitXorAssign,
                 ..
             },
             lhs,
diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
index 51c7d6fce31..0c17cc5d8f6 100644
--- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
@@ -10,7 +10,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, Item, ItemKind, Node, QPath
 use rustc_hir_analysis::lower_ty;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::{self, AssocKind, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::{Ident, kw};
 use rustc_span::{Span, sym};
@@ -322,7 +322,7 @@ impl UnconditionalRecursion {
                             .in_definition_order()
                             // We're not interested in foreign implementations of the `Default` trait.
                             .find(|item| {
-                                item.kind == AssocKind::Fn && item.def_id.is_local() && item.name == kw::Default
+                                item.is_fn() && item.def_id.is_local() && item.name() == kw::Default
                             })
                         && let Some(body_node) = cx.tcx.hir_get_if_local(assoc_item.def_id)
                         && let Some(body_id) = body_node.body_id()
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index f43715d6752..8966e6851ac 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -224,6 +224,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
 
     // We're trying to find whatever kind (~"constructor") we found in `alternatives[start..]`.
     let changed = match &mut focus_kind {
+        Missing => unreachable!(),
         // These pattern forms are "leafs" and do not have sub-patterns.
         // Therefore they are not some form of constructor `C`,
         // with which a pattern `C(p_0)` may be formed,
diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs
index 582aa6e6001..d0067b1a65e 100644
--- a/src/tools/clippy/clippy_lints/src/unused_self.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_self.rs
@@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf {
             .is_some()
         };
         if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind
-            && assoc_item.fn_has_self_parameter
+            && assoc_item.is_method()
             && let ImplItemKind::Fn(.., body_id) = &impl_item.kind
             && (!cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) || !self.avoid_breaking_exported_api)
             && let body = cx.tcx.hir_body(*body_id)
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 4309cd2c9ab..b7dcd2ffb0e 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -676,6 +676,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
         }
 
         match pat.value.kind {
+            PatKind::Missing => unreachable!(),
             PatKind::Wild => kind!("Wild"),
             PatKind::Never => kind!("Never"),
             PatKind::Binding(ann, _, name, sub) => {
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 eba576392eb..c5dce26143b 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
@@ -33,6 +33,7 @@ pub fn eq_id(l: Ident, r: Ident) -> bool {
 pub fn eq_pat(l: &Pat, r: &Pat) -> bool {
     use PatKind::*;
     match (&l.kind, &r.kind) {
+        (Missing, _) | (_, Missing) => unreachable!(),
         (Paren(l), _) => eq_pat(l, r),
         (_, Paren(r)) => eq_pat(l, r),
         (Wild, Wild) | (Rest, Rest) => true,
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index dd149c4a29b..17751e824c0 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -15,7 +15,7 @@ use rustc_apfloat::ieee::{Half, Quad};
 use rustc_ast::ast::{self, LitFloatType, LitKind};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{
-    BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, PatExpr, PatExprKind, QPath, UnOp,
+    BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, PatExpr, PatExprKind, QPath, UnOp,
 };
 use rustc_lexer::tokenize;
 use rustc_lint::LateContext;
@@ -506,7 +506,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
                 UnOp::Deref => Some(if let Constant::Ref(r) = o { *r } else { o }),
             }),
             ExprKind::If(cond, then, ref otherwise) => self.ifthenelse(cond, then, *otherwise),
-            ExprKind::Binary(op, left, right) => self.binop(op, left, right),
+            ExprKind::Binary(op, left, right) => self.binop(op.node, left, right),
             ExprKind::Call(callee, []) => {
                 // We only handle a few const functions for now.
                 if let ExprKind::Path(qpath) = &callee.kind
@@ -744,7 +744,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
         }
     }
 
-    fn binop(&self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Constant<'tcx>> {
+    fn binop(&self, op: BinOpKind, left: &Expr<'_>, right: &Expr<'_>) -> Option<Constant<'tcx>> {
         let l = self.expr(left)?;
         let r = self.expr(right);
         match (l, r) {
@@ -757,7 +757,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
 
                     // Using / or %, where the left-hand argument is the smallest integer of a signed integer type and
                     // the right-hand argument is -1 always panics, even with overflow-checks disabled
-                    if let BinOpKind::Div | BinOpKind::Rem = op.node
+                    if let BinOpKind::Div | BinOpKind::Rem = op
                         && l == ty_min_value
                         && r == -1
                     {
@@ -765,7 +765,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
                     }
 
                     let zext = |n: i128| Constant::Int(unsext(self.tcx, n, ity));
-                    match op.node {
+                    match op {
                         // When +, * or binary - create a value greater than the maximum value, or less than
                         // the minimum value that can be stored, it panics.
                         BinOpKind::Add => l.checked_add(r).and_then(|n| ity.ensure_fits(n)).map(zext),
@@ -792,7 +792,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
                 ty::Uint(ity) => {
                     let bits = ity.bits();
 
-                    match op.node {
+                    match op {
                         BinOpKind::Add => l.checked_add(r).and_then(|n| ity.ensure_fits(n)).map(Constant::Int),
                         BinOpKind::Sub => l.checked_sub(r).and_then(|n| ity.ensure_fits(n)).map(Constant::Int),
                         BinOpKind::Mul => l.checked_mul(r).and_then(|n| ity.ensure_fits(n)).map(Constant::Int),
@@ -815,7 +815,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
                 _ => None,
             },
             // FIXME(f16_f128): add these types when binary operations are available on all platforms
-            (Constant::F32(l), Some(Constant::F32(r))) => match op.node {
+            (Constant::F32(l), Some(Constant::F32(r))) => match op {
                 BinOpKind::Add => Some(Constant::F32(l + r)),
                 BinOpKind::Sub => Some(Constant::F32(l - r)),
                 BinOpKind::Mul => Some(Constant::F32(l * r)),
@@ -829,7 +829,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
                 BinOpKind::Gt => Some(Constant::Bool(l > r)),
                 _ => None,
             },
-            (Constant::F64(l), Some(Constant::F64(r))) => match op.node {
+            (Constant::F64(l), Some(Constant::F64(r))) => match op {
                 BinOpKind::Add => Some(Constant::F64(l + r)),
                 BinOpKind::Sub => Some(Constant::F64(l - r)),
                 BinOpKind::Mul => Some(Constant::F64(l * r)),
@@ -843,7 +843,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
                 BinOpKind::Gt => Some(Constant::Bool(l > r)),
                 _ => None,
             },
-            (l, r) => match (op.node, l, r) {
+            (l, r) => match (op, l, r) {
                 (BinOpKind::And, Constant::Bool(false), _) => Some(Constant::Bool(false)),
                 (BinOpKind::Or, Constant::Bool(true), _) => Some(Constant::Bool(true)),
                 (BinOpKind::And, Constant::Bool(true), Some(r)) | (BinOpKind::Or, Constant::Bool(false), Some(r)) => {
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 9938e64d242..b813cd361ed 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -1124,6 +1124,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
     pub fn hash_pat(&mut self, pat: &Pat<'_>) {
         std::mem::discriminant(&pat.kind).hash(&mut self.s);
         match pat.kind {
+            PatKind::Missing => unreachable!(),
             PatKind::Binding(BindingMode(by_ref, mutability), _, _, pat) => {
                 std::mem::discriminant(&by_ref).hash(&mut self.s);
                 std::mem::discriminant(&mutability).hash(&mut self.s);
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 8dc28fa3077..9f450d654d5 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -3,6 +3,7 @@
 #![feature(f128)]
 #![feature(f16)]
 #![feature(if_let_guard)]
+#![feature(macro_metavar_expr)]
 #![feature(macro_metavar_expr_concat)]
 #![feature(let_chains)]
 #![feature(never_type)]
@@ -74,6 +75,7 @@ pub mod qualify_min_const_fn;
 pub mod source;
 pub mod str_utils;
 pub mod sugg;
+pub mod sym;
 pub mod ty;
 pub mod usage;
 pub mod visitors;
@@ -114,6 +116,7 @@ use rustc_hir::{
 use rustc_lexer::{TokenKind, tokenize};
 use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::place::PlaceBase;
+use rustc_middle::lint::LevelAndSource;
 use rustc_middle::mir::{AggregateKind, Operand, RETURN_PLACE, Rvalue, StatementKind, TerminatorKind};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::fast_reject::SimplifiedType;
@@ -125,7 +128,7 @@ use rustc_middle::ty::{
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{Ident, Symbol, kw};
-use rustc_span::{InnerSpan, Span, sym};
+use rustc_span::{InnerSpan, Span};
 use visitors::{Visitable, for_each_unconsumed_temporary};
 
 use crate::consts::{ConstEvalCtxt, Constant, mir_to_const};
@@ -1857,6 +1860,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
     }
 
     match pat.kind {
+        PatKind::Missing => unreachable!(),
         PatKind::Wild | PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable.
         PatKind::Binding(_, _, _, pat) => pat.is_some_and(|pat| is_refutable(cx, pat)),
         PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
@@ -1976,14 +1980,14 @@ pub fn fulfill_or_allowed(cx: &LateContext<'_>, lint: &'static Lint, ids: impl I
     let mut suppress_lint = false;
 
     for id in ids {
-        let (level, _) = cx.tcx.lint_level_at_node(lint, id);
-        if let Some(expectation) = level.get_expectation_id() {
+        let LevelAndSource { level, lint_id, .. } = cx.tcx.lint_level_at_node(lint, id);
+        if let Some(expectation) = lint_id {
             cx.fulfill_expectation(expectation);
         }
 
         match level {
-            Level::Allow | Level::Expect(_) => suppress_lint = true,
-            Level::Warn | Level::ForceWarn(_) | Level::Deny | Level::Forbid => {},
+            Level::Allow | Level::Expect => suppress_lint = true,
+            Level::Warn | Level::ForceWarn | Level::Deny | Level::Forbid => {},
         }
     }
 
@@ -1998,7 +2002,7 @@ pub fn fulfill_or_allowed(cx: &LateContext<'_>, lint: &'static Lint, ids: impl I
 /// make sure to use `span_lint_hir` functions to emit the lint. This ensures that
 /// expectations at the checked nodes will be fulfilled.
 pub fn is_lint_allowed(cx: &LateContext<'_>, lint: &'static Lint, id: HirId) -> bool {
-    cx.tcx.lint_level_at_node(lint, id).0 == Level::Allow
+    cx.tcx.lint_level_at_node(lint, id).level == Level::Allow
 }
 
 pub fn strip_pat_refs<'hir>(mut pat: &'hir Pat<'hir>) -> &'hir Pat<'hir> {
@@ -3500,7 +3504,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St
                 // a::b::c  ::d::sym refers to
                 // e::f::sym:: ::
                 // result should be super::super::super::super::e::f
-                if let DefPathData::TypeNs(Some(s)) = l {
+                if let DefPathData::TypeNs(s) = l {
                     path.push(s.to_string());
                 }
                 if let DefPathData::TypeNs(_) = r {
@@ -3511,7 +3515,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St
             // a::b::sym:: ::    refers to
             // c::d::e  ::f::sym
             // when looking at `f`
-            Left(DefPathData::TypeNs(Some(sym))) => path.push(sym.to_string()),
+            Left(DefPathData::TypeNs(sym)) => path.push(sym.to_string()),
             // consider:
             // a::b::c  ::d::sym refers to
             // e::f::sym:: ::
@@ -3525,7 +3529,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St
         // `super` chain would be too long, just use the absolute path instead
         once(String::from("crate"))
             .chain(to.data.iter().filter_map(|el| {
-                if let DefPathData::TypeNs(Some(sym)) = el.data {
+                if let DefPathData::TypeNs(sym) = el.data {
                     Some(sym.to_string())
                 } else {
                     None
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 065d48119a2..e92c0c79b25 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -357,7 +357,7 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String {
     match op {
         AssocOp::Binary(op) => format!("{lhs} {} {rhs}", op.as_str()),
         AssocOp::Assign => format!("{lhs} = {rhs}"),
-        AssocOp::AssignOp(op) => format!("{lhs} {}= {rhs}", op.as_str()),
+        AssocOp::AssignOp(op) => format!("{lhs} {} {rhs}", op.as_str()),
         AssocOp::Cast => format!("{lhs} as {rhs}"),
         AssocOp::Range(limits) => format!("{lhs}{}{rhs}", limits.as_str()),
     }
diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs
new file mode 100644
index 00000000000..9cc72a5b3aa
--- /dev/null
+++ b/src/tools/clippy/clippy_utils/src/sym.rs
@@ -0,0 +1,23 @@
+#![allow(non_upper_case_globals)]
+
+use rustc_span::symbol::{Symbol, PREDEFINED_SYMBOLS_COUNT};
+
+pub use rustc_span::sym::*;
+
+macro_rules! generate {
+    ($($sym:ident,)*) => {
+        /// To be supplied to `rustc_interface::Config`
+        pub const EXTRA_SYMBOLS: &[&str] = &[
+            $(stringify!($sym),)*
+        ];
+
+        $(
+            pub const $sym: Symbol = Symbol::new(PREDEFINED_SYMBOLS_COUNT + ${index()});
+        )*
+    };
+}
+
+generate! {
+    rustfmt_skip,
+    unused_extern_crates,
+}
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs
index 6fdf4c244f8..d33e59342a5 100644
--- a/src/tools/clippy/clippy_utils/src/ty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -19,7 +19,7 @@ use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::traits::EvaluationResult;
 use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::{
-    self, AdtDef, AliasTy, AssocItem, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind,
+    self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind,
     GenericArgsRef, GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable,
     TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
 };
@@ -156,7 +156,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
 pub fn get_iterator_item_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
     cx.tcx
         .get_diagnostic_item(sym::Iterator)
-        .and_then(|iter_did| cx.get_associated_type(ty, iter_did, "Item"))
+        .and_then(|iter_did| cx.get_associated_type(ty, iter_did, sym::Item))
 }
 
 /// Get the diagnostic name of a type, e.g. `sym::HashMap`. To check if a type
@@ -1109,10 +1109,10 @@ pub fn make_projection<'tcx>(
         assoc_ty: Symbol,
         args: GenericArgsRef<'tcx>,
     ) -> Option<AliasTy<'tcx>> {
-        let Some(assoc_item) = tcx.associated_items(container_id).find_by_name_and_kind(
+        let Some(assoc_item) = tcx.associated_items(container_id).find_by_ident_and_kind(
             tcx,
             Ident::with_dummy_span(assoc_ty),
-            AssocKind::Type,
+            AssocTag::Type,
             container_id,
         ) else {
             debug_assert!(false, "type `{assoc_ty}` not found in `{container_id:?}`");
@@ -1345,7 +1345,7 @@ pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_n
                 .associated_items(did)
                 .filter_by_name_unhygienic(method_name)
                 .next()
-                .filter(|item| item.kind == AssocKind::Fn)
+                .filter(|item| item.as_tag() == AssocTag::Fn)
         })
     } else {
         None
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index e4092bcd105..df9c4e8e6ae 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -160,6 +160,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks {
             clippy_lints::register_lints(lint_store, conf);
             clippy_lints::register_pre_expansion_lints(lint_store, conf);
         }));
+        config.extra_symbols = clippy_utils::sym::EXTRA_SYMBOLS.into();
 
         // FIXME: #4825; This is required, because Clippy lints that are based on MIR have to be
         // run on the unoptimized MIR. On the other hand this results in some false negatives. If
diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml
index 4f8e475e762..ba1b8f25658 100644
--- a/src/tools/compiletest/Cargo.toml
+++ b/src/tools/compiletest/Cargo.toml
@@ -1,31 +1,33 @@
 [package]
 name = "compiletest"
 version = "0.0.0"
-edition = "2021"
+edition = "2024"
 
 [lib]
 doctest = false
 
 [dependencies]
+# tidy-alphabetical-start
 anstyle-svg = "0.1.3"
+build_helper = { path = "../../build_helper" }
+camino = "1"
 colored = "2"
 diff = "0.1.10"
-unified-diff = "0.2.1"
 getopts = "0.2"
+glob = "0.3.0"
+home = "0.5.5"
 indexmap = "2.0.0"
 miropt-test-tools = { path = "../miropt-test-tools" }
-build_helper = { path = "../../build_helper" }
-tracing = "0.1"
-tracing-subscriber = { version = "0.3.3", default-features = false, features = ["ansi", "env-filter", "fmt", "parking_lot", "smallvec"] }
 regex = "1.0"
+rustfix = "0.8.1"
 semver = { version = "1.0.23", features = ["serde"] }
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
-rustfix = "0.8.1"
+tracing = "0.1"
+tracing-subscriber = { version = "0.3.3", default-features = false, features = ["ansi", "env-filter", "fmt", "parking_lot", "smallvec"] }
+unified-diff = "0.2.1"
 walkdir = "2"
-glob = "0.3.0"
-anyhow = "1"
-home = "0.5.5"
+# tidy-alphabetical-end
 
 [target.'cfg(unix)'.dependencies]
 libc = "0.2"
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 08d3c1c343e..31c696ed41f 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -1,18 +1,17 @@
 use std::collections::{BTreeSet, HashMap, HashSet};
-use std::ffi::OsString;
-use std::path::{Path, PathBuf};
 use std::process::Command;
 use std::str::FromStr;
 use std::sync::OnceLock;
 use std::{fmt, iter};
 
 use build_helper::git::GitConfig;
+use camino::{Utf8Path, Utf8PathBuf};
 use semver::Version;
 use serde::de::{Deserialize, Deserializer, Error as _};
-use test::{ColorConfig, OutputFormat};
 
 pub use self::Mode::*;
-use crate::util::{PathBufExt, add_dylib_path};
+use crate::executor::{ColorConfig, OutputFormat};
+use crate::util::{Utf8PathBufExt, add_dylib_path};
 
 macro_rules! string_enum {
     ($(#[$meta:meta])* $vis:vis enum $name:ident { $($variant:ident => $repr:expr,)* }) => {
@@ -178,26 +177,30 @@ pub struct Config {
     /// `true` to overwrite stderr/stdout files instead of complaining about changes in output.
     pub bless: bool,
 
+    /// Stop as soon as possible after any test fails.
+    /// May run a few more tests before stopping, due to threading.
+    pub fail_fast: bool,
+
     /// The library paths required for running the compiler.
-    pub compile_lib_path: PathBuf,
+    pub compile_lib_path: Utf8PathBuf,
 
     /// The library paths required for running compiled programs.
-    pub run_lib_path: PathBuf,
+    pub run_lib_path: Utf8PathBuf,
 
     /// The rustc executable.
-    pub rustc_path: PathBuf,
+    pub rustc_path: Utf8PathBuf,
 
     /// The cargo executable.
-    pub cargo_path: Option<PathBuf>,
+    pub cargo_path: Option<Utf8PathBuf>,
 
     /// Rustc executable used to compile run-make recipes.
-    pub stage0_rustc_path: Option<PathBuf>,
+    pub stage0_rustc_path: Option<Utf8PathBuf>,
 
     /// The rustdoc executable.
-    pub rustdoc_path: Option<PathBuf>,
+    pub rustdoc_path: Option<Utf8PathBuf>,
 
     /// The coverage-dump executable.
-    pub coverage_dump_path: Option<PathBuf>,
+    pub coverage_dump_path: Option<Utf8PathBuf>,
 
     /// The Python executable to use for LLDB and htmldocck.
     pub python: String,
@@ -209,27 +212,27 @@ pub struct Config {
     pub jsondoclint_path: Option<String>,
 
     /// The LLVM `FileCheck` binary path.
-    pub llvm_filecheck: Option<PathBuf>,
+    pub llvm_filecheck: Option<Utf8PathBuf>,
 
     /// Path to LLVM's bin directory.
-    pub llvm_bin_dir: Option<PathBuf>,
+    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.
     pub run_clang_based_tests_with: Option<String>,
 
     /// The directory containing the sources.
-    pub src_root: PathBuf,
+    pub src_root: Utf8PathBuf,
     /// The directory containing the test suite sources. Must be a subdirectory of `src_root`.
-    pub src_test_suite_root: PathBuf,
+    pub src_test_suite_root: Utf8PathBuf,
 
     /// Root build directory (e.g. `build/`).
-    pub build_root: PathBuf,
+    pub build_root: Utf8PathBuf,
     /// Test suite specific build directory (e.g. `build/host/test/ui/`).
-    pub build_test_suite_root: PathBuf,
+    pub build_test_suite_root: Utf8PathBuf,
 
     /// The directory containing the compiler sysroot
-    pub sysroot_base: PathBuf,
+    pub sysroot_base: Utf8PathBuf,
 
     /// The number of the stage under test.
     pub stage: u32,
@@ -271,9 +274,6 @@ pub struct Config {
     /// Explicitly enable or disable running.
     pub run: Option<bool>,
 
-    /// Write out a parseable log of tests that were run
-    pub logfile: Option<PathBuf>,
-
     /// A command line to prefix program execution with,
     /// for running under valgrind for example.
     ///
@@ -300,7 +300,7 @@ pub struct Config {
     pub host: String,
 
     /// Path to / name of the Microsoft Console Debugger (CDB) executable
-    pub cdb: Option<OsString>,
+    pub cdb: Option<Utf8PathBuf>,
 
     /// Version of CDB
     pub cdb_version: Option<[u16; 4]>,
@@ -321,7 +321,7 @@ pub struct Config {
     pub system_llvm: bool,
 
     /// Path to the android tools
-    pub android_cross_path: PathBuf,
+    pub android_cross_path: Utf8PathBuf,
 
     /// Extra parameter to run adb on arm-linux-androideabi
     pub adb_path: String,
@@ -345,7 +345,7 @@ pub struct Config {
     pub color: ColorConfig,
 
     /// where to find the remote test client process, if we're using it
-    pub remote_test_client: Option<PathBuf>,
+    pub remote_test_client: Option<Utf8PathBuf>,
 
     /// mode describing what file the actual ui output will be compared to
     pub compare_mode: Option<CompareMode>,
@@ -394,6 +394,7 @@ pub struct Config {
 
     pub target_cfgs: OnceLock<TargetCfgs>,
     pub builtin_cfg_names: OnceLock<HashSet<String>>,
+    pub supported_crate_types: OnceLock<HashSet<String>>,
 
     pub nocapture: bool,
 
@@ -412,7 +413,12 @@ pub struct Config {
     /// 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.
-    pub minicore_path: PathBuf,
+    pub minicore_path: Utf8PathBuf,
+
+    /// If true, run tests with the "new" executor that was written to replace
+    /// compiletest's dependency on libtest. Eventually this will become the
+    /// default, and the libtest dependency will be removed.
+    pub new_executor: bool,
 }
 
 impl Config {
@@ -471,6 +477,11 @@ impl Config {
         self.builtin_cfg_names.get_or_init(|| builtin_cfg_names(self))
     }
 
+    /// Get the list of crate types that the target platform supports.
+    pub fn supported_crate_types(&self) -> &HashSet<String> {
+        self.supported_crate_types.get_or_init(|| supported_crate_types(self))
+    }
+
     pub fn has_threads(&self) -> bool {
         // Wasm targets don't have threads unless `-threads` is in the target
         // name, such as `wasm32-wasip1-threads`.
@@ -744,6 +755,31 @@ fn builtin_cfg_names(config: &Config) -> HashSet<String> {
     .collect()
 }
 
+pub const KNOWN_CRATE_TYPES: &[&str] =
+    &["bin", "cdylib", "dylib", "lib", "proc-macro", "rlib", "staticlib"];
+
+fn supported_crate_types(config: &Config) -> HashSet<String> {
+    let crate_types: HashSet<_> = rustc_output(
+        config,
+        &["--target", &config.target, "--print=supported-crate-types", "-Zunstable-options"],
+        Default::default(),
+    )
+    .lines()
+    .map(|l| l.to_string())
+    .collect();
+
+    for crate_type in crate_types.iter() {
+        assert!(
+            KNOWN_CRATE_TYPES.contains(&crate_type.as_str()),
+            "unexpected crate type `{}`: known crate types are {:?}",
+            crate_type,
+            KNOWN_CRATE_TYPES
+        );
+    }
+
+    crate_types
+}
+
 fn rustc_output(config: &Config, args: &[&str], envs: HashMap<String, String>) -> String {
     let mut command = Command::new(&config.rustc_path);
     add_dylib_path(&mut command, iter::once(&config.compile_lib_path));
@@ -772,8 +808,8 @@ fn serde_parse_u32<'de, D: Deserializer<'de>>(deserializer: D) -> Result<u32, D:
 
 #[derive(Debug, Clone)]
 pub struct TestPaths {
-    pub file: PathBuf,         // e.g., compile-test/foo/bar/baz.rs
-    pub relative_dir: PathBuf, // e.g., foo/bar
+    pub file: Utf8PathBuf,         // e.g., compile-test/foo/bar/baz.rs
+    pub relative_dir: Utf8PathBuf, // e.g., foo/bar
 }
 
 /// Used by `ui` tests to generate things like `foo.stderr` from `foo.rs`.
@@ -782,7 +818,7 @@ pub fn expected_output_path(
     revision: Option<&str>,
     compare_mode: &Option<CompareMode>,
     kind: &str,
-) -> PathBuf {
+) -> Utf8PathBuf {
     assert!(UI_EXTENSIONS.contains(&kind));
     let mut parts = Vec::new();
 
@@ -833,7 +869,7 @@ pub const UI_COVERAGE_MAP: &str = "cov-map";
 /// ```
 ///
 /// This is created early when tests are collected to avoid race conditions.
-pub fn output_relative_path(config: &Config, relative_dir: &Path) -> PathBuf {
+pub fn output_relative_path(config: &Config, relative_dir: &Utf8Path) -> Utf8PathBuf {
     config.build_test_suite_root.join(relative_dir)
 }
 
@@ -842,10 +878,10 @@ pub fn output_testname_unique(
     config: &Config,
     testpaths: &TestPaths,
     revision: Option<&str>,
-) -> PathBuf {
+) -> Utf8PathBuf {
     let mode = config.compare_mode.as_ref().map_or("", |m| m.to_str());
     let debugger = config.debugger.as_ref().map_or("", |m| m.to_str());
-    PathBuf::from(&testpaths.file.file_stem().unwrap())
+    Utf8PathBuf::from(&testpaths.file.file_stem().unwrap())
         .with_extra_extension(config.mode.output_dir_disambiguator())
         .with_extra_extension(revision.unwrap_or(""))
         .with_extra_extension(mode)
@@ -855,7 +891,11 @@ pub fn output_testname_unique(
 /// Absolute path to the directory where all output for the given
 /// test/revision should reside. Example:
 ///   /path/to/build/host-tuple/test/ui/relative/testname.revision.mode/
-pub fn output_base_dir(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
+pub fn output_base_dir(
+    config: &Config,
+    testpaths: &TestPaths,
+    revision: Option<&str>,
+) -> Utf8PathBuf {
     output_relative_path(config, &testpaths.relative_dir)
         .join(output_testname_unique(config, testpaths, revision))
 }
@@ -863,12 +903,20 @@ pub fn output_base_dir(config: &Config, testpaths: &TestPaths, revision: Option<
 /// Absolute path to the base filename used as output for the given
 /// test/revision. Example:
 ///   /path/to/build/host-tuple/test/ui/relative/testname.revision.mode/testname
-pub fn output_base_name(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
+pub fn output_base_name(
+    config: &Config,
+    testpaths: &TestPaths,
+    revision: Option<&str>,
+) -> Utf8PathBuf {
     output_base_dir(config, testpaths, revision).join(testpaths.file.file_stem().unwrap())
 }
 
 /// Absolute path to the directory to use for incremental compilation. Example:
 ///   /path/to/build/host-tuple/test/ui/relative/testname.mode/testname.inc
-pub fn incremental_dir(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
+pub fn incremental_dir(
+    config: &Config,
+    testpaths: &TestPaths,
+    revision: Option<&str>,
+) -> Utf8PathBuf {
     output_base_name(config, testpaths, revision).with_extension("inc")
 }
diff --git a/src/tools/compiletest/src/compute_diff.rs b/src/tools/compiletest/src/compute_diff.rs
index 4c942c51bae..509e7e11703 100644
--- a/src/tools/compiletest/src/compute_diff.rs
+++ b/src/tools/compiletest/src/compute_diff.rs
@@ -1,6 +1,7 @@
 use std::collections::VecDeque;
 use std::fs::{File, FileType};
-use std::path::Path;
+
+use camino::Utf8Path;
 
 #[derive(Debug, PartialEq)]
 pub enum DiffLine {
@@ -112,8 +113,8 @@ pub(crate) fn write_diff(expected: &str, actual: &str, context_size: usize) -> S
 /// Returns whether any data was actually written.
 pub(crate) fn write_filtered_diff<Filter>(
     diff_filename: &str,
-    out_dir: &Path,
-    compare_dir: &Path,
+    out_dir: &Utf8Path,
+    compare_dir: &Utf8Path,
     verbose: bool,
     filter: Filter,
 ) -> bool
@@ -123,19 +124,21 @@ where
     use std::io::{Read, Write};
     let mut diff_output = File::create(diff_filename).unwrap();
     let mut wrote_data = false;
-    for entry in walkdir::WalkDir::new(out_dir) {
+    for entry in walkdir::WalkDir::new(out_dir.as_std_path()) {
         let entry = entry.expect("failed to read file");
         let extension = entry.path().extension().and_then(|p| p.to_str());
         if filter(entry.file_type(), extension) {
-            let expected_path = compare_dir.join(entry.path().strip_prefix(&out_dir).unwrap());
+            let expected_path = compare_dir
+                .as_std_path()
+                .join(entry.path().strip_prefix(&out_dir.as_std_path()).unwrap());
             let expected = if let Ok(s) = std::fs::read(&expected_path) { s } else { continue };
             let actual_path = entry.path();
             let actual = std::fs::read(&actual_path).unwrap();
             let diff = unified_diff::diff(
                 &expected,
-                &expected_path.to_string_lossy(),
+                &expected_path.to_str().unwrap(),
                 &actual,
-                &actual_path.to_string_lossy(),
+                &actual_path.to_str().unwrap(),
                 3,
             );
             wrote_data |= !diff.is_empty();
diff --git a/src/tools/compiletest/src/debuggers.rs b/src/tools/compiletest/src/debuggers.rs
index 20e3c8dfb9e..c133d7fd4fb 100644
--- a/src/tools/compiletest/src/debuggers.rs
+++ b/src/tools/compiletest/src/debuggers.rs
@@ -1,9 +1,9 @@
 use std::env;
-use std::ffi::OsString;
-use std::path::{Path, PathBuf};
 use std::process::Command;
 use std::sync::Arc;
 
+use camino::{Utf8Path, Utf8PathBuf};
+
 use crate::common::{Config, Debugger};
 
 pub(crate) fn configure_cdb(config: &Config) -> Option<Arc<Config>> {
@@ -40,7 +40,9 @@ pub(crate) fn configure_gdb(config: &Config) -> Option<Arc<Config>> {
         //
         // we should figure out how to lift this restriction! (run them all
         // on different ports allocated dynamically).
-        env::set_var("RUST_TEST_THREADS", "1");
+        //
+        // SAFETY: at this point we are still single-threaded.
+        unsafe { env::set_var("RUST_TEST_THREADS", "1") };
     }
 
     Some(Arc::new(Config { debugger: Some(Debugger::Gdb), ..config.clone() }))
@@ -76,12 +78,15 @@ fn is_pc_windows_msvc_target(target: &str) -> bool {
     target.ends_with("-pc-windows-msvc")
 }
 
-fn find_cdb(target: &str) -> Option<OsString> {
+fn find_cdb(target: &str) -> Option<Utf8PathBuf> {
     if !(cfg!(windows) && is_pc_windows_msvc_target(target)) {
         return None;
     }
 
-    let pf86 = env::var_os("ProgramFiles(x86)").or_else(|| env::var_os("ProgramFiles"))?;
+    let pf86 = Utf8PathBuf::from_path_buf(
+        env::var_os("ProgramFiles(x86)").or_else(|| env::var_os("ProgramFiles"))?.into(),
+    )
+    .unwrap();
     let cdb_arch = if cfg!(target_arch = "x86") {
         "x86"
     } else if cfg!(target_arch = "x86_64") {
@@ -94,8 +99,7 @@ fn find_cdb(target: &str) -> Option<OsString> {
         return None; // No compatible CDB.exe in the Windows 10 SDK
     };
 
-    let mut path = PathBuf::new();
-    path.push(pf86);
+    let mut path = pf86;
     path.push(r"Windows Kits\10\Debuggers"); // We could check 8.1 etc. too?
     path.push(cdb_arch);
     path.push(r"cdb.exe");
@@ -104,15 +108,15 @@ fn find_cdb(target: &str) -> Option<OsString> {
         return None;
     }
 
-    Some(path.into_os_string())
+    Some(path)
 }
 
 /// Returns Path to CDB
 pub(crate) fn analyze_cdb(
     cdb: Option<String>,
     target: &str,
-) -> (Option<OsString>, Option<[u16; 4]>) {
-    let cdb = cdb.map(OsString::from).or_else(|| find_cdb(target));
+) -> (Option<Utf8PathBuf>, Option<[u16; 4]>) {
+    let cdb = cdb.map(Utf8PathBuf::from).or_else(|| find_cdb(target));
 
     let mut version = None;
     if let Some(cdb) = cdb.as_ref() {
@@ -141,7 +145,7 @@ pub(crate) fn extract_cdb_version(full_version_line: &str) -> Option<[u16; 4]> {
 pub(crate) fn analyze_gdb(
     gdb: Option<String>,
     target: &str,
-    android_cross_path: &Path,
+    android_cross_path: &Utf8Path,
 ) -> (Option<String>, Option<u32>) {
     #[cfg(not(windows))]
     const GDB_FALLBACK: &str = "gdb";
@@ -150,10 +154,7 @@ pub(crate) fn analyze_gdb(
 
     let fallback_gdb = || {
         if is_android_gdb_target(target) {
-            let mut gdb_path = match android_cross_path.to_str() {
-                Some(x) => x.to_owned(),
-                None => panic!("cannot find android cross path"),
-            };
+            let mut gdb_path = android_cross_path.to_string();
             gdb_path.push_str("/bin/gdb");
             gdb_path
         } else {
diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs
index b2ad5a3b3d0..086a8a67456 100644
--- a/src/tools/compiletest/src/directive-list.rs
+++ b/src/tools/compiletest/src/directive-list.rs
@@ -22,6 +22,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "dont-check-compiler-stderr",
     "dont-check-compiler-stdout",
     "dont-check-failure-status",
+    "dont-require-annotations",
     "edition",
     "error-pattern",
     "exact-llvm-major-version",
@@ -132,6 +133,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "min-llvm-version",
     "min-system-llvm-version",
     "needs-asm-support",
+    "needs-crate-type",
     "needs-deterministic-layouts",
     "needs-dlltool",
     "needs-dynamic-linking",
diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs
index b68f817146f..3bb98276bf5 100644
--- a/src/tools/compiletest/src/errors.rs
+++ b/src/tools/compiletest/src/errors.rs
@@ -2,14 +2,13 @@ use std::fmt;
 use std::fs::File;
 use std::io::BufReader;
 use std::io::prelude::*;
-use std::path::Path;
-use std::str::FromStr;
 use std::sync::OnceLock;
 
+use camino::Utf8Path;
 use regex::Regex;
 use tracing::*;
 
-#[derive(Copy, Clone, Debug, PartialEq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub enum ErrorKind {
     Help,
     Error,
@@ -18,30 +17,48 @@ pub enum ErrorKind {
     Warning,
 }
 
-impl FromStr for ErrorKind {
-    type Err = ();
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        let s = s.to_uppercase();
-        let part0: &str = s.split(':').next().unwrap();
-        match part0 {
-            "HELP" => Ok(ErrorKind::Help),
-            "ERROR" => Ok(ErrorKind::Error),
-            "NOTE" => Ok(ErrorKind::Note),
-            "SUGGESTION" => Ok(ErrorKind::Suggestion),
-            "WARN" | "WARNING" => Ok(ErrorKind::Warning),
-            _ => Err(()),
+impl ErrorKind {
+    pub fn from_compiler_str(s: &str) -> ErrorKind {
+        match s {
+            "help" => ErrorKind::Help,
+            "error" | "error: internal compiler error" => ErrorKind::Error,
+            "note" | "failure-note" => ErrorKind::Note,
+            "warning" => ErrorKind::Warning,
+            _ => panic!("unexpected compiler diagnostic kind `{s}`"),
         }
     }
+
+    /// Either the canonical uppercase string, or some additional versions for compatibility.
+    /// FIXME: consider keeping only the canonical versions here.
+    fn from_user_str(s: &str) -> Option<ErrorKind> {
+        Some(match s {
+            "HELP" | "help" => ErrorKind::Help,
+            "ERROR" | "error" => ErrorKind::Error,
+            "NOTE" | "note" => ErrorKind::Note,
+            "SUGGESTION" => ErrorKind::Suggestion,
+            "WARN" | "WARNING" | "warn" | "warning" => ErrorKind::Warning,
+            _ => return None,
+        })
+    }
+
+    pub fn expect_from_user_str(s: &str) -> ErrorKind {
+        ErrorKind::from_user_str(s).unwrap_or_else(|| {
+            panic!(
+                "unexpected diagnostic kind `{s}`, expected \
+                 `ERROR`, `WARN`, `NOTE`, `HELP` or `SUGGESTION`"
+            )
+        })
+    }
 }
 
 impl fmt::Display for ErrorKind {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
-            ErrorKind::Help => write!(f, "help message"),
-            ErrorKind::Error => write!(f, "error"),
-            ErrorKind::Note => write!(f, "note"),
-            ErrorKind::Suggestion => write!(f, "suggestion"),
-            ErrorKind::Warning => write!(f, "warning"),
+            ErrorKind::Help => write!(f, "HELP"),
+            ErrorKind::Error => write!(f, "ERROR"),
+            ErrorKind::Note => write!(f, "NOTE"),
+            ErrorKind::Suggestion => write!(f, "SUGGESTION"),
+            ErrorKind::Warning => write!(f, "WARN"),
         }
     }
 }
@@ -53,6 +70,10 @@ pub struct Error {
     /// `None` if not specified or unknown message kind.
     pub kind: Option<ErrorKind>,
     pub msg: String,
+    /// For some `Error`s, like secondary lines of multi-line diagnostics, line annotations
+    /// are not mandatory, even if they would otherwise be mandatory for primary errors.
+    /// Only makes sense for "actual" errors, not for "expected" errors.
+    pub require_annotation: bool,
 }
 
 impl Error {
@@ -60,7 +81,7 @@ impl Error {
         use colored::Colorize;
         format!(
             "{: <10}line {: >3}: {}",
-            self.kind.map(|kind| kind.to_string()).unwrap_or_default().to_uppercase(),
+            self.kind.map(|kind| kind.to_string()).unwrap_or_default(),
             self.line_num_str(),
             self.msg.cyan(),
         )
@@ -81,8 +102,8 @@ impl Error {
 ///
 /// If revision is not None, then we look
 /// for `//[X]~` instead, where `X` is the current revision.
-pub fn load_errors(testfile: &Path, revision: Option<&str>) -> Vec<Error> {
-    let rdr = BufReader::new(File::open(testfile).unwrap());
+pub fn load_errors(testfile: &Utf8Path, revision: Option<&str>) -> Vec<Error> {
+    let rdr = BufReader::new(File::open(testfile.as_std_path()).unwrap());
 
     // `last_nonfollow_error` tracks the most recently seen
     // line with an error template that did not use the
@@ -150,18 +171,12 @@ fn parse_expected(
     }
 
     // Get the part of the comment after the sigil (e.g. `~^^` or ~|).
-    let whole_match = captures.get(0).unwrap();
-    let (_, mut msg) = line.split_at(whole_match.end());
-
-    let first_word = msg.split_whitespace().next().expect("Encountered unexpected empty comment");
-
-    // If we find `//~ ERROR foo` or something like that, skip the first word.
-    let kind = first_word.parse::<ErrorKind>().ok();
-    if kind.is_some() {
-        msg = &msg.trim_start().split_at(first_word.len()).1;
-    }
-
-    let msg = msg.trim().to_owned();
+    let tag = captures.get(0).unwrap();
+    let rest = line[tag.end()..].trim_start();
+    let (kind_str, _) = rest.split_once(|c: char| !c.is_ascii_alphabetic()).unwrap_or((rest, ""));
+    let kind = ErrorKind::from_user_str(kind_str);
+    let untrimmed_msg = if kind.is_some() { &rest[kind_str.len()..] } else { rest };
+    let msg = untrimmed_msg.strip_prefix(':').unwrap_or(untrimmed_msg).trim().to_owned();
 
     let line_num_adjust = &captures["adjust"];
     let (follow_prev, line_num) = if line_num_adjust == "|" {
@@ -177,12 +192,12 @@ fn parse_expected(
     debug!(
         "line={:?} tag={:?} follow_prev={:?} kind={:?} msg={:?}",
         line_num,
-        whole_match.as_str(),
+        tag.as_str(),
         follow_prev,
         kind,
         msg
     );
-    Some((follow_prev, Error { line_num, kind, msg }))
+    Some((follow_prev, Error { line_num, kind, msg, require_annotation: true }))
 }
 
 #[cfg(test)]
diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs
new file mode 100644
index 00000000000..0c173d476af
--- /dev/null
+++ b/src/tools/compiletest/src/executor.rs
@@ -0,0 +1,293 @@
+//! This module contains a reimplementation of the subset of libtest
+//! functionality needed by compiletest.
+
+use std::borrow::Cow;
+use std::collections::HashMap;
+use std::hash::{BuildHasherDefault, DefaultHasher};
+use std::num::NonZero;
+use std::sync::{Arc, Mutex, mpsc};
+use std::{env, hint, io, mem, panic, thread};
+
+use crate::common::{Config, TestPaths};
+
+mod deadline;
+mod json;
+pub(crate) mod libtest;
+
+pub(crate) fn run_tests(config: &Config, tests: Vec<CollectedTest>) -> bool {
+    let tests_len = tests.len();
+    let filtered = filter_tests(config, tests);
+    // Iterator yielding tests that haven't been started yet.
+    let mut fresh_tests = (0..).map(TestId).zip(&filtered);
+
+    let concurrency = get_concurrency();
+    assert!(concurrency > 0);
+    let concurrent_capacity = concurrency.min(filtered.len());
+
+    let mut listener = json::Listener::new();
+    let mut running_tests = HashMap::with_capacity_and_hasher(
+        concurrent_capacity,
+        BuildHasherDefault::<DefaultHasher>::new(),
+    );
+    let mut deadline_queue = deadline::DeadlineQueue::with_capacity(concurrent_capacity);
+
+    let num_filtered_out = tests_len - filtered.len();
+    listener.suite_started(filtered.len(), num_filtered_out);
+
+    // Channel used by test threads to report the test outcome when done.
+    let (completion_tx, completion_rx) = mpsc::channel::<TestCompletion>();
+
+    // Unlike libtest, we don't have a separate code path for concurrency=1.
+    // In that case, the tests will effectively be run serially anyway.
+    loop {
+        // Spawn new test threads, up to the concurrency limit.
+        // FIXME(let_chains): Use a let-chain here when stable in bootstrap.
+        'spawn: while running_tests.len() < concurrency {
+            let Some((id, test)) = fresh_tests.next() else { break 'spawn };
+            listener.test_started(test);
+            deadline_queue.push(id, test);
+            let join_handle = spawn_test_thread(id, test, completion_tx.clone());
+            running_tests.insert(id, RunningTest { test, join_handle });
+        }
+
+        // If all running tests have finished, and there weren't any unstarted
+        // tests to spawn, then we're done.
+        if running_tests.is_empty() {
+            break;
+        }
+
+        let completion = deadline_queue
+            .read_channel_while_checking_deadlines(&completion_rx, |_id, test| {
+                listener.test_timed_out(test);
+            })
+            .expect("receive channel should never be closed early");
+
+        let RunningTest { test, join_handle } = running_tests.remove(&completion.id).unwrap();
+        if let Some(join_handle) = join_handle {
+            join_handle.join().unwrap_or_else(|_| {
+                panic!("thread for `{}` panicked after reporting completion", test.desc.name)
+            });
+        }
+
+        listener.test_finished(test, &completion);
+
+        if completion.outcome.is_failed() && config.fail_fast {
+            // Prevent any other in-flight threads from panicking when they
+            // write to the completion channel.
+            mem::forget(completion_rx);
+            break;
+        }
+    }
+
+    let suite_passed = listener.suite_finished();
+    suite_passed
+}
+
+/// Spawns a thread to run a single test, and returns the thread's join handle.
+///
+/// Returns `None` if the test was ignored, so no thread was spawned.
+fn spawn_test_thread(
+    id: TestId,
+    test: &CollectedTest,
+    completion_tx: mpsc::Sender<TestCompletion>,
+) -> Option<thread::JoinHandle<()>> {
+    if test.desc.ignore && !test.config.run_ignored {
+        completion_tx
+            .send(TestCompletion { id, outcome: TestOutcome::Ignored, stdout: None })
+            .unwrap();
+        return None;
+    }
+
+    let runnable_test = RunnableTest::new(test);
+    let should_panic = test.desc.should_panic;
+    let run_test = move || run_test_inner(id, should_panic, runnable_test, completion_tx);
+
+    let thread_builder = thread::Builder::new().name(test.desc.name.clone());
+    let join_handle = thread_builder.spawn(run_test).unwrap();
+    Some(join_handle)
+}
+
+/// Runs a single test, within the dedicated thread spawned by the caller.
+fn run_test_inner(
+    id: TestId,
+    should_panic: ShouldPanic,
+    runnable_test: RunnableTest,
+    completion_sender: mpsc::Sender<TestCompletion>,
+) {
+    let is_capture = !runnable_test.config.nocapture;
+    let capture_buf = is_capture.then(|| Arc::new(Mutex::new(vec![])));
+
+    if let Some(capture_buf) = &capture_buf {
+        io::set_output_capture(Some(Arc::clone(capture_buf)));
+    }
+
+    let panic_payload = panic::catch_unwind(move || runnable_test.run()).err();
+
+    if is_capture {
+        io::set_output_capture(None);
+    }
+
+    let outcome = match (should_panic, panic_payload) {
+        (ShouldPanic::No, None) | (ShouldPanic::Yes, Some(_)) => TestOutcome::Succeeded,
+        (ShouldPanic::No, Some(_)) => TestOutcome::Failed { message: None },
+        (ShouldPanic::Yes, None) => {
+            TestOutcome::Failed { message: Some("test did not panic as expected") }
+        }
+    };
+    let stdout = capture_buf.map(|mutex| mutex.lock().unwrap_or_else(|e| e.into_inner()).to_vec());
+
+    completion_sender.send(TestCompletion { id, outcome, stdout }).unwrap();
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+struct TestId(usize);
+
+struct RunnableTest {
+    config: Arc<Config>,
+    testpaths: TestPaths,
+    revision: Option<String>,
+}
+
+impl RunnableTest {
+    fn new(test: &CollectedTest) -> Self {
+        let config = Arc::clone(&test.config);
+        let testpaths = test.testpaths.clone();
+        let revision = test.revision.clone();
+        Self { config, testpaths, revision }
+    }
+
+    fn run(&self) {
+        __rust_begin_short_backtrace(|| {
+            crate::runtest::run(
+                Arc::clone(&self.config),
+                &self.testpaths,
+                self.revision.as_deref(),
+            );
+        });
+    }
+}
+
+/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
+#[inline(never)]
+fn __rust_begin_short_backtrace<T, F: FnOnce() -> T>(f: F) -> T {
+    let result = f();
+
+    // prevent this frame from being tail-call optimised away
+    hint::black_box(result)
+}
+
+struct RunningTest<'a> {
+    test: &'a CollectedTest,
+    join_handle: Option<thread::JoinHandle<()>>,
+}
+
+/// Test completion message sent by individual test threads when their test
+/// finishes (successfully or unsuccessfully).
+struct TestCompletion {
+    id: TestId,
+    outcome: TestOutcome,
+    stdout: Option<Vec<u8>>,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+enum TestOutcome {
+    Succeeded,
+    Failed { message: Option<&'static str> },
+    Ignored,
+}
+
+impl TestOutcome {
+    fn is_failed(&self) -> bool {
+        matches!(self, Self::Failed { .. })
+    }
+}
+
+/// Applies command-line arguments for filtering/skipping tests by name.
+///
+/// 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.
+fn filter_tests(opts: &Config, tests: Vec<CollectedTest>) -> Vec<CollectedTest> {
+    let mut filtered = tests;
+
+    let matches_filter = |test: &CollectedTest, filter_str: &str| {
+        let test_name = &test.desc.name;
+        if opts.filter_exact { test_name == filter_str } else { test_name.contains(filter_str) }
+    };
+
+    // Remove tests that don't match the test filter
+    if !opts.filters.is_empty() {
+        filtered.retain(|test| opts.filters.iter().any(|filter| matches_filter(test, filter)));
+    }
+
+    // Skip tests that match any of the skip filters
+    if !opts.skip.is_empty() {
+        filtered.retain(|test| !opts.skip.iter().any(|sf| matches_filter(test, sf)));
+    }
+
+    filtered
+}
+
+/// Determines the number of tests to run concurrently.
+///
+/// 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.
+fn get_concurrency() -> usize {
+    if let Ok(value) = env::var("RUST_TEST_THREADS") {
+        match value.parse::<NonZero<usize>>().ok() {
+            Some(n) => n.get(),
+            _ => panic!("RUST_TEST_THREADS is `{value}`, should be a positive integer."),
+        }
+    } else {
+        thread::available_parallelism().map(|n| n.get()).unwrap_or(1)
+    }
+}
+
+/// Information needed to create a `test::TestDescAndFn`.
+pub(crate) struct CollectedTest {
+    pub(crate) desc: CollectedTestDesc,
+    pub(crate) config: Arc<Config>,
+    pub(crate) testpaths: TestPaths,
+    pub(crate) revision: Option<String>,
+}
+
+/// Information needed to create a `test::TestDesc`.
+pub(crate) struct CollectedTestDesc {
+    pub(crate) name: String,
+    pub(crate) ignore: bool,
+    pub(crate) ignore_message: Option<Cow<'static, str>>,
+    pub(crate) should_panic: ShouldPanic,
+}
+
+/// Whether console output should be colored or not.
+#[derive(Copy, Clone, Default, Debug)]
+pub enum ColorConfig {
+    #[default]
+    AutoColor,
+    AlwaysColor,
+    NeverColor,
+}
+
+/// Format of the test results output.
+#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
+pub enum OutputFormat {
+    /// Verbose output
+    Pretty,
+    /// Quiet output
+    #[default]
+    Terse,
+    /// JSON output
+    Json,
+}
+
+/// Whether test is expected to panic or not.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub(crate) enum ShouldPanic {
+    No,
+    Yes,
+}
diff --git a/src/tools/compiletest/src/executor/deadline.rs b/src/tools/compiletest/src/executor/deadline.rs
new file mode 100644
index 00000000000..83b8591a416
--- /dev/null
+++ b/src/tools/compiletest/src/executor/deadline.rs
@@ -0,0 +1,78 @@
+use std::collections::VecDeque;
+use std::sync::mpsc::{self, RecvError, RecvTimeoutError};
+use std::time::{Duration, Instant};
+
+use crate::executor::{CollectedTest, TestId};
+
+const TEST_WARN_TIMEOUT_S: u64 = 60;
+
+struct DeadlineEntry<'a> {
+    id: TestId,
+    test: &'a CollectedTest,
+    deadline: Instant,
+}
+
+pub(crate) struct DeadlineQueue<'a> {
+    queue: VecDeque<DeadlineEntry<'a>>,
+}
+
+impl<'a> DeadlineQueue<'a> {
+    pub(crate) fn with_capacity(capacity: usize) -> Self {
+        Self { queue: VecDeque::with_capacity(capacity) }
+    }
+
+    pub(crate) fn push(&mut self, id: TestId, test: &'a CollectedTest) {
+        let deadline = Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S);
+        self.queue.push_back(DeadlineEntry { id, test, deadline });
+    }
+
+    /// Equivalent to `rx.read()`, except that if any test exceeds its deadline
+    /// during the wait, the given callback will also be called for that test.
+    pub(crate) fn read_channel_while_checking_deadlines<T>(
+        &mut self,
+        rx: &mpsc::Receiver<T>,
+        mut on_deadline_passed: impl FnMut(TestId, &CollectedTest),
+    ) -> Result<T, RecvError> {
+        loop {
+            let Some(next_deadline) = self.next_deadline() else {
+                // All currently-running tests have already exceeded their
+                // deadline, so do a normal receive.
+                return rx.recv();
+            };
+            let wait_duration = next_deadline.saturating_duration_since(Instant::now());
+
+            let recv_result = rx.recv_timeout(wait_duration);
+            match recv_result {
+                Ok(value) => return Ok(value),
+                Err(RecvTimeoutError::Timeout) => {
+                    // Notify the callback of tests that have exceeded their
+                    // deadline, then loop and do annother channel read.
+                    for DeadlineEntry { id, test, .. } in self.remove_tests_past_deadline() {
+                        on_deadline_passed(id, test);
+                    }
+                }
+                Err(RecvTimeoutError::Disconnected) => return Err(RecvError),
+            }
+        }
+    }
+
+    fn next_deadline(&self) -> Option<Instant> {
+        Some(self.queue.front()?.deadline)
+    }
+
+    fn remove_tests_past_deadline(&mut self) -> Vec<DeadlineEntry<'a>> {
+        let now = Instant::now();
+        let mut timed_out = vec![];
+        while let Some(deadline_entry) = pop_front_if(&mut self.queue, |entry| now < entry.deadline)
+        {
+            timed_out.push(deadline_entry);
+        }
+        timed_out
+    }
+}
+
+/// FIXME(vec_deque_pop_if): Use `VecDeque::pop_front_if` when it is stable in bootstrap.
+fn pop_front_if<T>(queue: &mut VecDeque<T>, predicate: impl FnOnce(&T) -> bool) -> Option<T> {
+    let first = queue.front()?;
+    if predicate(first) { queue.pop_front() } else { None }
+}
diff --git a/src/tools/compiletest/src/executor/json.rs b/src/tools/compiletest/src/executor/json.rs
new file mode 100644
index 00000000000..c74ed81a36b
--- /dev/null
+++ b/src/tools/compiletest/src/executor/json.rs
@@ -0,0 +1,111 @@
+//! Collects statistics and emits suite/test events as JSON messages, using
+//! the same JSON format as libtest's JSON formatter.
+//!
+//! These messages are then parsed by bootstrap, which replaces them with
+//! user-friendly terminal output.
+
+use std::time::Instant;
+
+use serde_json::json;
+
+use crate::executor::{CollectedTest, TestCompletion, TestOutcome};
+
+pub(crate) struct Listener {
+    suite_start: Option<Instant>,
+    passed: usize,
+    failed: usize,
+    ignored: usize,
+    filtered_out: usize,
+}
+
+impl Listener {
+    pub(crate) fn new() -> Self {
+        Self { suite_start: None, passed: 0, failed: 0, ignored: 0, filtered_out: 0 }
+    }
+
+    fn print_message(&self, message: &serde_json::Value) {
+        println!("{message}");
+    }
+
+    fn now(&self) -> Instant {
+        Instant::now()
+    }
+
+    pub(crate) fn suite_started(&mut self, test_count: usize, filtered_out: usize) {
+        self.suite_start = Some(self.now());
+        self.filtered_out = filtered_out;
+        let message = json!({ "type": "suite", "event": "started", "test_count": test_count });
+        self.print_message(&message);
+    }
+
+    pub(crate) fn test_started(&mut self, test: &CollectedTest) {
+        let name = test.desc.name.as_str();
+        let message = json!({ "type": "test", "event": "started", "name": name });
+        self.print_message(&message);
+    }
+
+    pub(crate) fn test_timed_out(&mut self, test: &CollectedTest) {
+        let name = test.desc.name.as_str();
+        let message = json!({ "type": "test", "event": "timeout", "name": name });
+        self.print_message(&message);
+    }
+
+    pub(crate) fn test_finished(&mut self, test: &CollectedTest, completion: &TestCompletion) {
+        let event;
+        let name = test.desc.name.as_str();
+        let mut maybe_message = None;
+        let maybe_stdout = completion.stdout.as_deref().map(String::from_utf8_lossy);
+
+        match completion.outcome {
+            TestOutcome::Succeeded => {
+                self.passed += 1;
+                event = "ok";
+            }
+            TestOutcome::Failed { message } => {
+                self.failed += 1;
+                maybe_message = message;
+                event = "failed";
+            }
+            TestOutcome::Ignored => {
+                self.ignored += 1;
+                maybe_message = test.desc.ignore_message.as_deref();
+                event = "ignored";
+            }
+        };
+
+        // This emits optional fields as `null`, instead of omitting them
+        // completely as libtest does, but bootstrap can parse the result
+        // either way.
+        let json = json!({
+            "type": "test",
+            "event": event,
+            "name": name,
+            "message": maybe_message,
+            "stdout": maybe_stdout,
+        });
+
+        self.print_message(&json);
+    }
+
+    pub(crate) fn suite_finished(&mut self) -> bool {
+        let exec_time = self.suite_start.map(|start| (self.now() - start).as_secs_f64());
+        let suite_passed = self.failed == 0;
+
+        let event = if suite_passed { "ok" } else { "failed" };
+        let message = json!({
+            "type": "suite",
+            "event": event,
+            "passed": self.passed,
+            "failed": self.failed,
+            "ignored": self.ignored,
+            // Compiletest doesn't run any benchmarks, but we still need to set this
+            // field to 0 so that bootstrap's JSON parser can read our message.
+            "measured": 0,
+            "filtered_out": self.filtered_out,
+            "exec_time": exec_time,
+        });
+
+        self.print_message(&message);
+        suite_passed
+    }
+}
diff --git a/src/tools/compiletest/src/executor/libtest.rs b/src/tools/compiletest/src/executor/libtest.rs
new file mode 100644
index 00000000000..032b3f4fa9a
--- /dev/null
+++ b/src/tools/compiletest/src/executor/libtest.rs
@@ -0,0 +1,111 @@
+//! This submodule encapsulates all of the code that actually interacts with
+//! libtest, so that it can be easily removed after the new executor becomes
+//! the default.
+
+use std::borrow::Cow;
+use std::io;
+
+use crate::common::Config;
+use crate::executor::{CollectedTest, CollectedTestDesc, ColorConfig, OutputFormat, ShouldPanic};
+
+/// Delegates to libtest to run the list of collected tests.
+///
+/// Returns `Ok(true)` if all tests passed, or `Ok(false)` if one or more tests failed.
+pub(crate) fn execute_tests(config: &Config, tests: Vec<CollectedTest>) -> io::Result<bool> {
+    let opts = test_opts(config);
+    let tests = tests.into_iter().map(|t| t.into_libtest()).collect::<Vec<_>>();
+
+    test::run_tests_console(&opts, tests)
+}
+
+impl CollectedTest {
+    fn into_libtest(self) -> test::TestDescAndFn {
+        let Self { desc, config, testpaths, revision } = self;
+        let CollectedTestDesc { name, ignore, ignore_message, should_panic } = desc;
+
+        // Libtest requires the ignore message to be a &'static str, so we might
+        // have to leak memory to create it. This is fine, as we only do so once
+        // per test, so the leak won't grow indefinitely.
+        let ignore_message = ignore_message.map(|msg| match msg {
+            Cow::Borrowed(s) => s,
+            Cow::Owned(s) => &*String::leak(s),
+        });
+
+        let desc = test::TestDesc {
+            name: test::DynTestName(name),
+            ignore,
+            ignore_message,
+            source_file: "",
+            start_line: 0,
+            start_col: 0,
+            end_line: 0,
+            end_col: 0,
+            should_panic: should_panic.to_libtest(),
+            compile_fail: false,
+            no_run: false,
+            test_type: test::TestType::Unknown,
+        };
+
+        // This closure is invoked when libtest returns control to compiletest
+        // to execute the test.
+        let testfn = test::DynTestFn(Box::new(move || {
+            crate::runtest::run(config, &testpaths, revision.as_deref());
+            Ok(())
+        }));
+
+        test::TestDescAndFn { desc, testfn }
+    }
+}
+
+impl ColorConfig {
+    fn to_libtest(self) -> test::ColorConfig {
+        match self {
+            Self::AutoColor => test::ColorConfig::AutoColor,
+            Self::AlwaysColor => test::ColorConfig::AlwaysColor,
+            Self::NeverColor => test::ColorConfig::NeverColor,
+        }
+    }
+}
+
+impl OutputFormat {
+    fn to_libtest(self) -> test::OutputFormat {
+        match self {
+            Self::Pretty => test::OutputFormat::Pretty,
+            Self::Terse => test::OutputFormat::Terse,
+            Self::Json => test::OutputFormat::Json,
+        }
+    }
+}
+
+impl ShouldPanic {
+    fn to_libtest(self) -> test::ShouldPanic {
+        match self {
+            Self::No => test::ShouldPanic::No,
+            Self::Yes => test::ShouldPanic::Yes,
+        }
+    }
+}
+
+fn test_opts(config: &Config) -> test::TestOpts {
+    test::TestOpts {
+        exclude_should_panic: false,
+        filters: config.filters.clone(),
+        filter_exact: config.filter_exact,
+        run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No },
+        format: config.format.to_libtest(),
+        logfile: None,
+        run_tests: true,
+        bench_benchmarks: true,
+        nocapture: config.nocapture,
+        color: config.color.to_libtest(),
+        shuffle: false,
+        shuffle_seed: None,
+        test_threads: None,
+        skip: config.skip.clone(),
+        list: false,
+        options: test::Options::new(),
+        time_options: None,
+        force_run_in_process: false,
+        fail_fast: config.fail_fast,
+    }
+}
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index f654bd9c90b..2b203bb309c 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -3,14 +3,16 @@ use std::env;
 use std::fs::File;
 use std::io::BufReader;
 use std::io::prelude::*;
-use std::path::{Path, PathBuf};
 use std::process::Command;
 
+use camino::{Utf8Path, Utf8PathBuf};
 use semver::Version;
 use tracing::*;
 
 use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
 use crate::debuggers::{extract_cdb_version, extract_gdb_version};
+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::util::static_regex;
@@ -43,12 +45,12 @@ pub struct EarlyProps {
 }
 
 impl EarlyProps {
-    pub fn from_file(config: &Config, testfile: &Path) -> Self {
-        let file = File::open(testfile).expect("open test file to parse earlyprops");
+    pub fn from_file(config: &Config, testfile: &Utf8Path) -> Self {
+        let file = File::open(testfile.as_std_path()).expect("open test file to parse earlyprops");
         Self::from_reader(config, testfile, file)
     }
 
-    pub fn from_reader<R: Read>(config: &Config, testfile: &Path, rdr: R) -> Self {
+    pub fn from_reader<R: Read>(config: &Config, testfile: &Utf8Path, rdr: R) -> Self {
         let mut props = EarlyProps::default();
         let mut poisoned = false;
         iter_header(
@@ -64,7 +66,7 @@ impl EarlyProps {
         );
 
         if poisoned {
-            eprintln!("errors encountered during EarlyProps parsing: {}", testfile.display());
+            eprintln!("errors encountered during EarlyProps parsing: {}", testfile);
             panic!("errors encountered during EarlyProps parsing");
         }
 
@@ -86,7 +88,7 @@ pub struct TestProps {
     pub doc_flags: Vec<String>,
     // If present, the name of a file that this test should match when
     // pretty-printed
-    pub pp_exact: Option<PathBuf>,
+    pub pp_exact: Option<Utf8PathBuf>,
     /// Auxiliary crates that should be built and made available to this test.
     pub(crate) aux: AuxProps,
     // Environment settings to use for compiling
@@ -132,7 +134,7 @@ pub struct TestProps {
     // not set by end-users; rather it is set by the incremental
     // testing harness and used when generating compilation
     // arguments. (In particular, it propagates to the aux-builds.)
-    pub incremental_dir: Option<PathBuf>,
+    pub incremental_dir: Option<Utf8PathBuf>,
     // If `true`, this test will use incremental compilation.
     //
     // This can be set manually with the `incremental` header, or implicitly
@@ -195,6 +197,8 @@ pub struct TestProps {
     /// Build and use `minicore` as `core` stub for `no_core` tests in cross-compilation scenarios
     /// that don't otherwise want/need `-Z build-std`.
     pub add_core_stubs: bool,
+    /// Whether line annotatins are required for the given error kind.
+    pub dont_require_annotations: HashSet<ErrorKind>,
 }
 
 mod directives {
@@ -211,6 +215,7 @@ mod directives {
     pub const CHECK_RUN_RESULTS: &'static str = "check-run-results";
     pub const DONT_CHECK_COMPILER_STDOUT: &'static str = "dont-check-compiler-stdout";
     pub const DONT_CHECK_COMPILER_STDERR: &'static str = "dont-check-compiler-stderr";
+    pub const DONT_REQUIRE_ANNOTATIONS: &'static str = "dont-require-annotations";
     pub const NO_PREFER_DYNAMIC: &'static str = "no-prefer-dynamic";
     pub const PRETTY_MODE: &'static str = "pretty-mode";
     pub const PRETTY_COMPARE_ONLY: &'static str = "pretty-compare-only";
@@ -296,10 +301,16 @@ impl TestProps {
             no_auto_check_cfg: false,
             has_enzyme: false,
             add_core_stubs: false,
+            dont_require_annotations: Default::default(),
         }
     }
 
-    pub fn from_aux_file(&self, testfile: &Path, revision: Option<&str>, config: &Config) -> Self {
+    pub fn from_aux_file(
+        &self,
+        testfile: &Utf8Path,
+        revision: Option<&str>,
+        config: &Config,
+    ) -> Self {
         let mut props = TestProps::new();
 
         // copy over select properties to the aux build:
@@ -310,10 +321,10 @@ impl TestProps {
         props
     }
 
-    pub fn from_file(testfile: &Path, revision: Option<&str>, config: &Config) -> Self {
+    pub fn from_file(testfile: &Utf8Path, revision: Option<&str>, config: &Config) -> Self {
         let mut props = TestProps::new();
         props.load_from(testfile, revision, config);
-        props.exec_env.push(("RUSTC".to_string(), config.rustc_path.display().to_string()));
+        props.exec_env.push(("RUSTC".to_string(), config.rustc_path.to_string()));
 
         match (props.pass_mode, props.fail_mode) {
             (None, None) if config.mode == Mode::Ui => props.fail_mode = Some(FailMode::Check),
@@ -328,10 +339,10 @@ impl TestProps {
     /// tied to a particular revision `foo` (indicated by writing
     /// `//@[foo]`), then the property is ignored unless `test_revision` is
     /// `Some("foo")`.
-    fn load_from(&mut self, testfile: &Path, test_revision: Option<&str>, config: &Config) {
+    fn load_from(&mut self, testfile: &Utf8Path, test_revision: Option<&str>, config: &Config) {
         let mut has_edition = false;
         if !testfile.is_dir() {
-            let file = File::open(testfile).unwrap();
+            let file = File::open(testfile.as_std_path()).unwrap();
 
             let mut poisoned = false;
 
@@ -377,14 +388,22 @@ impl TestProps {
                     }
 
                     if let Some(flags) = config.parse_name_value_directive(ln, COMPILE_FLAGS) {
-                        self.compile_flags.extend(split_flags(&flags));
+                        let flags = split_flags(&flags);
+                        for flag in &flags {
+                            if flag == "--edition" || flag.starts_with("--edition=") {
+                                panic!("you must use `//@ edition` to configure the edition");
+                            }
+                        }
+                        self.compile_flags.extend(flags);
                     }
                     if config.parse_name_value_directive(ln, INCORRECT_COMPILER_FLAGS).is_some() {
                         panic!("`compiler-flags` directive should be spelled `compile-flags`");
                     }
 
                     if let Some(edition) = config.parse_edition(ln) {
-                        self.compile_flags.push(format!("--edition={}", edition.trim()));
+                        // The edition is added at the start, since flags from //@compile-flags must
+                        // be passed to rustc last.
+                        self.compile_flags.insert(0, format!("--edition={}", edition.trim()));
                         has_edition = true;
                     }
 
@@ -440,7 +459,7 @@ impl TestProps {
                         ln,
                         UNSET_EXEC_ENV,
                         &mut self.unset_exec_env,
-                        |r| r,
+                        |r| r.trim().to_owned(),
                     );
                     config.push_name_value_directive(
                         ln,
@@ -452,7 +471,7 @@ impl TestProps {
                         ln,
                         UNSET_RUSTC_ENV,
                         &mut self.unset_rustc_env,
-                        |r| r,
+                        |r| r.trim().to_owned(),
                     );
                     config.push_name_value_directive(
                         ln,
@@ -569,11 +588,18 @@ impl TestProps {
                     config.set_name_directive(ln, NO_AUTO_CHECK_CFG, &mut self.no_auto_check_cfg);
 
                     self.update_add_core_stubs(ln, config);
+
+                    if let Some(err_kind) =
+                        config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS)
+                    {
+                        self.dont_require_annotations
+                            .insert(ErrorKind::expect_from_user_str(err_kind.trim()));
+                    }
                 },
             );
 
             if poisoned {
-                eprintln!("errors encountered during TestProps parsing: {}", testfile.display());
+                eprintln!("errors encountered during TestProps parsing: {}", testfile);
                 panic!("errors encountered during TestProps parsing");
             }
         }
@@ -605,7 +631,9 @@ impl TestProps {
         }
 
         if let (Some(edition), false) = (&config.edition, has_edition) {
-            self.compile_flags.push(format!("--edition={}", edition));
+            // The edition is added at the start, since flags from //@compile-flags must be passed
+            // to rustc last.
+            self.compile_flags.insert(0, format!("--edition={}", edition));
         }
     }
 
@@ -842,7 +870,7 @@ fn iter_header(
     mode: Mode,
     _suite: &str,
     poisoned: &mut bool,
-    testfile: &Path,
+    testfile: &Utf8Path,
     rdr: impl Read,
     it: &mut dyn FnMut(DirectiveLine<'_>),
 ) {
@@ -894,9 +922,7 @@ fn iter_header(
 
                 eprintln!(
                     "error: detected unknown compiletest test directive `{}` in {}:{}",
-                    directive_line.raw_directive,
-                    testfile.display(),
-                    line_number,
+                    directive_line.raw_directive, testfile, line_number,
                 );
 
                 return;
@@ -908,10 +934,7 @@ fn iter_header(
                 eprintln!(
                     "error: detected trailing compiletest test directive `{}` in {}:{}\n \
                       help: put the trailing directive in it's own line: `//@ {}`",
-                    trailing_directive,
-                    testfile.display(),
-                    line_number,
-                    trailing_directive,
+                    trailing_directive, testfile, line_number, trailing_directive,
                 );
 
                 return;
@@ -923,7 +946,12 @@ fn iter_header(
 }
 
 impl Config {
-    fn parse_and_update_revisions(&self, testfile: &Path, line: &str, existing: &mut Vec<String>) {
+    fn parse_and_update_revisions(
+        &self,
+        testfile: &Utf8Path,
+        line: &str,
+        existing: &mut Vec<String>,
+    ) {
         const FORBIDDEN_REVISION_NAMES: [&str; 2] = [
             // `//@ revisions: true false` Implying `--cfg=true` and `--cfg=false` makes it very
             // weird for the test, since if the test writer wants a cfg of the same revision name
@@ -936,26 +964,19 @@ impl Config {
 
         if let Some(raw) = self.parse_name_value_directive(line, "revisions") {
             if self.mode == Mode::RunMake {
-                panic!("`run-make` tests do not support revisions: {}", testfile.display());
+                panic!("`run-make` tests do not support revisions: {}", testfile);
             }
 
             let mut duplicates: HashSet<_> = existing.iter().cloned().collect();
             for revision in raw.split_whitespace() {
                 if !duplicates.insert(revision.to_string()) {
-                    panic!(
-                        "duplicate revision: `{}` in line `{}`: {}",
-                        revision,
-                        raw,
-                        testfile.display()
-                    );
+                    panic!("duplicate revision: `{}` in line `{}`: {}", revision, raw, testfile);
                 }
 
                 if FORBIDDEN_REVISION_NAMES.contains(&revision) {
                     panic!(
                         "revision name `{revision}` is not permitted: `{}` in line `{}`: {}",
-                        revision,
-                        raw,
-                        testfile.display()
+                        revision, raw, testfile
                     );
                 }
 
@@ -966,8 +987,7 @@ impl Config {
                         "revision name `{revision}` is not permitted in a test suite that uses \
                         `FileCheck` annotations as it is confusing when used as custom `FileCheck` \
                         prefix: `{revision}` in line `{}`: {}",
-                        raw,
-                        testfile.display()
+                        raw, testfile
                     );
                 }
 
@@ -978,23 +998,20 @@ impl Config {
 
     fn parse_env(nv: String) -> (String, String) {
         // nv is either FOO or FOO=BAR
-        let mut strs: Vec<String> = nv.splitn(2, '=').map(str::to_owned).collect();
-
-        match strs.len() {
-            1 => (strs.pop().unwrap(), String::new()),
-            2 => {
-                let end = strs.pop().unwrap();
-                (strs.pop().unwrap(), end)
-            }
-            n => panic!("Expected 1 or 2 strings, not {}", n),
-        }
+        // FIXME(Zalathar): The form without `=` seems to be unused; should
+        // we drop support for it?
+        let (name, value) = nv.split_once('=').unwrap_or((&nv, ""));
+        // Trim whitespace from the name, so that `//@ exec-env: FOO=BAR`
+        // sees the name as `FOO` and not ` FOO`.
+        let name = name.trim();
+        (name.to_owned(), value.to_owned())
     }
 
-    fn parse_pp_exact(&self, line: &str, testfile: &Path) -> Option<PathBuf> {
+    fn parse_pp_exact(&self, line: &str, testfile: &Utf8Path) -> Option<Utf8PathBuf> {
         if let Some(s) = self.parse_name_value_directive(line, "pp-exact") {
-            Some(PathBuf::from(&s))
+            Some(Utf8PathBuf::from(&s))
         } else if self.parse_name_directive(line, "pp-exact") {
-            testfile.file_name().map(PathBuf::from)
+            testfile.file_name().map(Utf8PathBuf::from)
         } else {
             None
         }
@@ -1100,20 +1117,19 @@ fn expand_variables(mut value: String, config: &Config) -> String {
 
     if value.contains(CWD) {
         let cwd = env::current_dir().unwrap();
-        value = value.replace(CWD, &cwd.to_string_lossy());
+        value = value.replace(CWD, &cwd.to_str().unwrap());
     }
 
     if value.contains(SRC_BASE) {
-        value = value.replace(SRC_BASE, &config.src_test_suite_root.to_str().unwrap());
+        value = value.replace(SRC_BASE, &config.src_test_suite_root.as_str());
     }
 
     if value.contains(TEST_SUITE_BUILD_BASE) {
-        value =
-            value.replace(TEST_SUITE_BUILD_BASE, &config.build_test_suite_root.to_str().unwrap());
+        value = value.replace(TEST_SUITE_BUILD_BASE, &config.build_test_suite_root.as_str());
     }
 
     if value.contains(SYSROOT_BASE) {
-        value = value.replace(SYSROOT_BASE, &config.sysroot_base.to_str().unwrap());
+        value = value.replace(SYSROOT_BASE, &config.sysroot_base.as_str());
     }
 
     if value.contains(TARGET_LINKER) {
@@ -1126,9 +1142,9 @@ fn expand_variables(mut value: String, config: &Config) -> String {
 
     if value.contains(RUST_SRC_BASE) {
         let src_base = config.sysroot_base.join("lib/rustlib/src/rust");
-        src_base.try_exists().expect(&*format!("{} should exists", src_base.display()));
-        let src_base = src_base.read_link().unwrap_or(src_base);
-        value = value.replace(RUST_SRC_BASE, &src_base.to_string_lossy());
+        src_base.try_exists().expect(&*format!("{} should exists", src_base));
+        let src_base = src_base.read_link_utf8().unwrap_or(src_base);
+        value = value.replace(RUST_SRC_BASE, &src_base.as_str());
     }
 
     value
@@ -1231,14 +1247,14 @@ pub fn llvm_has_libzstd(config: &Config) -> bool {
     // contains a path to that static lib, and that it exists.
     //
     // See compiler/rustc_llvm/build.rs for more details and similar expectations.
-    fn is_zstd_in_config(llvm_bin_dir: &Path) -> Option<()> {
+    fn is_zstd_in_config(llvm_bin_dir: &Utf8Path) -> Option<()> {
         let llvm_config_path = llvm_bin_dir.join("llvm-config");
         let output = Command::new(llvm_config_path).arg("--system-libs").output().ok()?;
         assert!(output.status.success(), "running llvm-config --system-libs failed");
 
         let libs = String::from_utf8(output.stdout).ok()?;
         for lib in libs.split_whitespace() {
-            if lib.ends_with("libzstd.a") && Path::new(lib).exists() {
+            if lib.ends_with("libzstd.a") && Utf8Path::new(lib).exists() {
                 return Some(());
             }
         }
@@ -1256,7 +1272,7 @@ pub fn llvm_has_libzstd(config: &Config) -> bool {
     // `lld` supports it. If not, an error will be emitted: "LLVM was not built with
     // LLVM_ENABLE_ZSTD or did not find zstd at build time".
     #[cfg(unix)]
-    fn is_lld_built_with_zstd(llvm_bin_dir: &Path) -> Option<()> {
+    fn is_lld_built_with_zstd(llvm_bin_dir: &Utf8Path) -> Option<()> {
         let lld_path = llvm_bin_dir.join("lld");
         if lld_path.exists() {
             // We can't call `lld` as-is, it expects to be invoked by a compiler driver using a
@@ -1292,7 +1308,7 @@ pub fn llvm_has_libzstd(config: &Config) -> bool {
     }
 
     #[cfg(not(unix))]
-    fn is_lld_built_with_zstd(_llvm_bin_dir: &Path) -> Option<()> {
+    fn is_lld_built_with_zstd(_llvm_bin_dir: &Utf8Path) -> Option<()> {
         None
     }
 
@@ -1355,15 +1371,15 @@ where
     Some((min, max))
 }
 
-pub fn make_test_description<R: Read>(
+pub(crate) fn make_test_description<R: Read>(
     config: &Config,
     cache: &HeadersCache,
-    name: test::TestName,
-    path: &Path,
+    name: String,
+    path: &Utf8Path,
     src: R,
     test_revision: Option<&str>,
     poisoned: &mut bool,
-) -> test::TestDesc {
+) -> CollectedTestDesc {
     let mut ignore = false;
     let mut ignore_message = None;
     let mut should_fail = false;
@@ -1387,13 +1403,10 @@ pub fn make_test_description<R: Read>(
                     match $e {
                         IgnoreDecision::Ignore { reason } => {
                             ignore = true;
-                            // The ignore reason must be a &'static str, so we have to leak memory to
-                            // create it. This is fine, as the header is parsed only at the start of
-                            // compiletest so it won't grow indefinitely.
-                            ignore_message = Some(&*Box::leak(Box::<str>::from(reason)));
+                            ignore_message = Some(reason.into());
                         }
                         IgnoreDecision::Error { message } => {
-                            eprintln!("error: {}:{line_number}: {message}", path.display());
+                            eprintln!("error: {}:{line_number}: {message}", path);
                             *poisoned = true;
                             return;
                         }
@@ -1423,7 +1436,7 @@ pub fn make_test_description<R: Read>(
     );
 
     if local_poisoned {
-        eprintln!("errors encountered when trying to make test description: {}", path.display());
+        eprintln!("errors encountered when trying to make test description: {}", path);
         panic!("errors encountered when trying to make test description");
     }
 
@@ -1431,25 +1444,12 @@ pub fn make_test_description<R: Read>(
     // since we run the pretty printer across all tests by default.
     // If desired, we could add a `should-fail-pretty` annotation.
     let should_panic = match config.mode {
-        crate::common::Pretty => test::ShouldPanic::No,
-        _ if should_fail => test::ShouldPanic::Yes,
-        _ => test::ShouldPanic::No,
+        crate::common::Pretty => ShouldPanic::No,
+        _ if should_fail => ShouldPanic::Yes,
+        _ => ShouldPanic::No,
     };
 
-    test::TestDesc {
-        name,
-        ignore,
-        ignore_message,
-        source_file: "",
-        start_line: 0,
-        start_col: 0,
-        end_line: 0,
-        end_col: 0,
-        should_panic,
-        compile_fail: false,
-        no_run: false,
-        test_type: test::TestType::Unknown,
-    }
+    CollectedTestDesc { name, ignore, ignore_message, should_panic }
 }
 
 fn ignore_cdb(config: &Config, line: &str) -> IgnoreDecision {
@@ -1545,7 +1545,7 @@ fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision {
     IgnoreDecision::Continue
 }
 
-fn ignore_llvm(config: &Config, path: &Path, line: &str) -> IgnoreDecision {
+fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
     if let Some(needed_components) =
         config.parse_name_value_directive(line, "needs-llvm-components")
     {
@@ -1557,8 +1557,7 @@ fn ignore_llvm(config: &Config, path: &Path, line: &str) -> IgnoreDecision {
             if env::var_os("COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS").is_some() {
                 panic!(
                     "missing LLVM component {}, and COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS is set: {}",
-                    missing_component,
-                    path.display()
+                    missing_component, path
                 );
             }
             return IgnoreDecision::Ignore {
diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs
index 12f0790fb10..2ace40c490b 100644
--- a/src/tools/compiletest/src/header/needs.rs
+++ b/src/tools/compiletest/src/header/needs.rs
@@ -1,4 +1,4 @@
-use crate::common::{Config, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer};
+use crate::common::{Config, KNOWN_CRATE_TYPES, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer};
 use crate::header::{IgnoreDecision, llvm_has_libzstd};
 
 pub(super) fn handle_needs(
@@ -6,7 +6,7 @@ pub(super) fn handle_needs(
     config: &Config,
     ln: &str,
 ) -> IgnoreDecision {
-    // Note thet we intentionally still put the needs- prefix here to make the file show up when
+    // Note that we intentionally still put the needs- prefix here to make the file show up when
     // grepping for a directive name, even though we could technically strip that.
     let needs = &[
         Need {
@@ -224,6 +224,50 @@ pub(super) fn handle_needs(
         }
     }
 
+    // FIXME(jieyouxu): share multi-value directive logic with `needs-target-has-atomic` above.
+    if name == "needs-crate-type" {
+        let Some(rest) = rest else {
+            return IgnoreDecision::Error {
+                message:
+                    "expected `needs-crate-type` to have a comma-separated list of crate types"
+                        .to_string(),
+            };
+        };
+
+        // Expect directive value to be a list of comma-separated crate-types.
+        let specified_crate_types = rest
+            .split(',')
+            .map(|crate_type| crate_type.trim())
+            .map(ToString::to_string)
+            .collect::<Vec<String>>();
+
+        for crate_type in &specified_crate_types {
+            if !KNOWN_CRATE_TYPES.contains(&crate_type.as_str()) {
+                return IgnoreDecision::Error {
+                    message: format!(
+                        "unknown crate type specified in `needs-crate-type`: `{crate_type}` is not \
+                        a known crate type, known values are `{:?}`",
+                        KNOWN_CRATE_TYPES
+                    ),
+                };
+            }
+        }
+
+        let satisfies_all_crate_types = specified_crate_types
+            .iter()
+            .all(|specified| config.supported_crate_types().contains(specified));
+        if satisfies_all_crate_types {
+            return IgnoreDecision::Continue;
+        } else {
+            return IgnoreDecision::Ignore {
+                reason: format!(
+                    "skipping test as target does not support all of the crate types `{:?}`",
+                    specified_crate_types
+                ),
+            };
+        }
+    }
+
     if !name.starts_with("needs-") {
         return IgnoreDecision::Continue;
     }
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index 4d90f152ee2..3a8c3748de9 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -1,6 +1,6 @@
 use std::io::Read;
-use std::path::Path;
 
+use camino::Utf8Path;
 use semver::Version;
 
 use super::{
@@ -8,14 +8,15 @@ use super::{
     parse_normalize_rule,
 };
 use crate::common::{Config, Debugger, Mode};
+use crate::executor::{CollectedTestDesc, ShouldPanic};
 
 fn make_test_description<R: Read>(
     config: &Config,
-    name: test::TestName,
-    path: &Path,
+    name: String,
+    path: &Utf8Path,
     src: R,
     revision: Option<&str>,
-) -> test::TestDesc {
+) -> CollectedTestDesc {
     let cache = HeadersCache::load(config);
     let mut poisoned = false;
     let test = crate::header::make_test_description(
@@ -229,12 +230,12 @@ fn cfg() -> ConfigBuilder {
 
 fn parse_rs(config: &Config, contents: &str) -> EarlyProps {
     let bytes = contents.as_bytes();
-    EarlyProps::from_reader(config, Path::new("a.rs"), bytes)
+    EarlyProps::from_reader(config, Utf8Path::new("a.rs"), bytes)
 }
 
 fn check_ignore(config: &Config, contents: &str) -> bool {
-    let tn = test::DynTestName(String::new());
-    let p = Path::new("a.rs");
+    let tn = String::new();
+    let p = Utf8Path::new("a.rs");
     let d = make_test_description(&config, tn, p, std::io::Cursor::new(contents), None);
     d.ignore
 }
@@ -242,13 +243,13 @@ fn check_ignore(config: &Config, contents: &str) -> bool {
 #[test]
 fn should_fail() {
     let config: Config = cfg().build();
-    let tn = test::DynTestName(String::new());
-    let p = Path::new("a.rs");
+    let tn = String::new();
+    let p = Utf8Path::new("a.rs");
 
     let d = make_test_description(&config, tn.clone(), p, std::io::Cursor::new(""), None);
-    assert_eq!(d.should_panic, test::ShouldPanic::No);
+    assert_eq!(d.should_panic, ShouldPanic::No);
     let d = make_test_description(&config, tn, p, std::io::Cursor::new("//@ should-fail"), None);
-    assert_eq!(d.should_panic, test::ShouldPanic::Yes);
+    assert_eq!(d.should_panic, ShouldPanic::Yes);
 }
 
 #[test]
@@ -458,9 +459,6 @@ fn profiler_runtime() {
 #[test]
 fn asm_support() {
     let asms = [
-        #[cfg(bootstrap)]
-        ("avr-unknown-gnu-atmega328", false),
-        #[cfg(not(bootstrap))]
         ("avr-none", false),
         ("i686-unknown-netbsd", true),
         ("riscv32gc-unknown-linux-gnu", true),
@@ -786,7 +784,7 @@ fn threads_support() {
     }
 }
 
-fn run_path(poisoned: &mut bool, path: &Path, buf: &[u8]) {
+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 |_| {});
 }
@@ -796,7 +794,7 @@ fn test_unknown_directive_check() {
     let mut poisoned = false;
     run_path(
         &mut poisoned,
-        Path::new("a.rs"),
+        Utf8Path::new("a.rs"),
         include_bytes!("./test-auxillary/unknown_directive.rs"),
     );
     assert!(poisoned);
@@ -807,7 +805,7 @@ fn test_known_directive_check_no_error() {
     let mut poisoned = false;
     run_path(
         &mut poisoned,
-        Path::new("a.rs"),
+        Utf8Path::new("a.rs"),
         include_bytes!("./test-auxillary/known_directive.rs"),
     );
     assert!(!poisoned);
@@ -818,7 +816,7 @@ fn test_error_annotation_no_error() {
     let mut poisoned = false;
     run_path(
         &mut poisoned,
-        Path::new("a.rs"),
+        Utf8Path::new("a.rs"),
         include_bytes!("./test-auxillary/error_annotation.rs"),
     );
     assert!(!poisoned);
@@ -829,7 +827,7 @@ fn test_non_rs_unknown_directive_not_checked() {
     let mut poisoned = false;
     run_path(
         &mut poisoned,
-        Path::new("a.Makefile"),
+        Utf8Path::new("a.Makefile"),
         include_bytes!("./test-auxillary/not_rs.Makefile"),
     );
     assert!(!poisoned);
@@ -838,21 +836,21 @@ fn test_non_rs_unknown_directive_not_checked() {
 #[test]
 fn test_trailing_directive() {
     let mut poisoned = false;
-    run_path(&mut poisoned, Path::new("a.rs"), b"//@ only-x86 only-arm");
+    run_path(&mut poisoned, Utf8Path::new("a.rs"), b"//@ only-x86 only-arm");
     assert!(poisoned);
 }
 
 #[test]
 fn test_trailing_directive_with_comment() {
     let mut poisoned = false;
-    run_path(&mut poisoned, Path::new("a.rs"), b"//@ only-x86   only-arm with comment");
+    run_path(&mut poisoned, Utf8Path::new("a.rs"), b"//@ only-x86   only-arm with comment");
     assert!(poisoned);
 }
 
 #[test]
 fn test_not_trailing_directive() {
     let mut poisoned = false;
-    run_path(&mut poisoned, Path::new("a.rs"), b"//@ revisions: incremental");
+    run_path(&mut poisoned, Utf8Path::new("a.rs"), b"//@ revisions: incremental");
     assert!(!poisoned);
 }
 
@@ -904,3 +902,41 @@ fn test_rustc_abi() {
     assert!(!check_ignore(&config, "//@ ignore-rustc_abi-x86-sse2"));
     assert!(check_ignore(&config, "//@ only-rustc_abi-x86-sse2"));
 }
+
+#[test]
+fn test_supported_crate_types() {
+    // Basic assumptions check on under-test compiler's `--print=supported-crate-types` output based
+    // on knowledge about the cherry-picked `x86_64-unknown-linux-gnu` and `wasm32-unknown-unknown`
+    // targets. Also smoke tests the `needs-crate-type` directive itself.
+
+    use std::collections::HashSet;
+
+    let config = cfg().target("x86_64-unknown-linux-gnu").build();
+    assert_eq!(
+        config.supported_crate_types().iter().map(String::as_str).collect::<HashSet<_>>(),
+        HashSet::from(["bin", "cdylib", "dylib", "lib", "proc-macro", "rlib", "staticlib"]),
+    );
+    assert!(!check_ignore(&config, "//@ needs-crate-type: rlib"));
+    assert!(!check_ignore(&config, "//@ needs-crate-type: dylib"));
+    assert!(!check_ignore(
+        &config,
+        "//@ needs-crate-type: bin, cdylib, dylib, lib, proc-macro, rlib, staticlib"
+    ));
+
+    let config = cfg().target("wasm32-unknown-unknown").build();
+    assert_eq!(
+        config.supported_crate_types().iter().map(String::as_str).collect::<HashSet<_>>(),
+        HashSet::from(["bin", "cdylib", "lib", "rlib", "staticlib"]),
+    );
+
+    // rlib is supported
+    assert!(!check_ignore(&config, "//@ needs-crate-type: rlib"));
+    // dylib is not
+    assert!(check_ignore(&config, "//@ needs-crate-type: dylib"));
+    // If multiple crate types are specified, then all specified crate types need to be supported.
+    assert!(check_ignore(&config, "//@ needs-crate-type: cdylib, dylib"));
+    assert!(check_ignore(
+        &config,
+        "//@ needs-crate-type: bin, cdylib, dylib, lib, proc-macro, rlib, staticlib"
+    ));
+}
diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs
index 9bc26fedf8f..62fe538ee32 100644
--- a/src/tools/compiletest/src/json.rs
+++ b/src/tools/compiletest/src/json.rs
@@ -1,7 +1,6 @@
 //! These structs are a subset of the ones found in `rustc_errors::json`.
 
 use std::path::{Path, PathBuf};
-use std::str::FromStr;
 use std::sync::OnceLock;
 
 use regex::Regex;
@@ -142,43 +141,34 @@ pub fn extract_rendered(output: &str) -> String {
 }
 
 pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
-    output.lines().flat_map(|line| parse_line(file_name, line, output, proc_res)).collect()
-}
-
-fn parse_line(file_name: &str, line: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
-    // The compiler sometimes intermingles non-JSON stuff into the
-    // output.  This hack just skips over such lines. Yuck.
-    if line.starts_with('{') {
-        match serde_json::from_str::<Diagnostic>(line) {
-            Ok(diagnostic) => {
-                let mut expected_errors = vec![];
-                push_expected_errors(&mut expected_errors, &diagnostic, &[], file_name);
-                expected_errors
-            }
-            Err(error) => {
-                // Ignore the future compat report message - this is handled
-                // by `extract_rendered`
-                if serde_json::from_str::<FutureIncompatReport>(line).is_ok() {
-                    vec![]
-                } else {
-                    proc_res.fatal(
+    let mut errors = Vec::new();
+    for line in output.lines() {
+        // The compiler sometimes intermingles non-JSON stuff into the
+        // output.  This hack just skips over such lines. Yuck.
+        if line.starts_with('{') {
+            match serde_json::from_str::<Diagnostic>(line) {
+                Ok(diagnostic) => push_actual_errors(&mut errors, &diagnostic, &[], file_name),
+                Err(error) => {
+                    // Ignore the future compat report message - this is handled
+                    // by `extract_rendered`
+                    if serde_json::from_str::<FutureIncompatReport>(line).is_err() {
+                        proc_res.fatal(
                         Some(&format!(
-                            "failed to decode compiler output as json: \
-                         `{}`\nline: {}\noutput: {}",
+                            "failed to decode compiler output as json: `{}`\nline: {}\noutput: {}",
                             error, line, output
                         )),
                         || (),
                     );
+                    }
                 }
             }
         }
-    } else {
-        vec![]
     }
+    errors
 }
 
-fn push_expected_errors(
-    expected_errors: &mut Vec<Error>,
+fn push_actual_errors(
+    errors: &mut Vec<Error>,
     diagnostic: &Diagnostic,
     default_spans: &[&DiagnosticSpan],
     file_name: &str,
@@ -236,44 +226,47 @@ fn push_expected_errors(
         }
     };
 
-    // Convert multi-line messages into multiple expected
-    // errors. We expect to replace these with something
-    // more structured shortly anyhow.
+    // Convert multi-line messages into multiple errors.
+    // We expect to replace these with something more structured anyhow.
     let mut message_lines = diagnostic.message.lines();
-    if let Some(first_line) = message_lines.next() {
-        let ignore = |s| {
-            static RE: OnceLock<Regex> = OnceLock::new();
-            RE.get_or_init(|| {
-                Regex::new(r"aborting due to \d+ previous errors?|\d+ warnings? emitted").unwrap()
-            })
-            .is_match(s)
-        };
-
-        if primary_spans.is_empty() && !ignore(first_line) {
-            let msg = with_code(None, first_line);
-            let kind = ErrorKind::from_str(&diagnostic.level).ok();
-            expected_errors.push(Error { line_num: None, kind, msg });
-        } else {
-            for span in primary_spans {
-                let msg = with_code(Some(span), first_line);
-                let kind = ErrorKind::from_str(&diagnostic.level).ok();
-                expected_errors.push(Error { line_num: Some(span.line_start), kind, msg });
-            }
+    let kind = Some(ErrorKind::from_compiler_str(&diagnostic.level));
+    let first_line = message_lines.next().unwrap_or(&diagnostic.message);
+    if primary_spans.is_empty() {
+        static RE: OnceLock<Regex> = OnceLock::new();
+        let re_init =
+            || Regex::new(r"aborting due to \d+ previous errors?|\d+ warnings? emitted").unwrap();
+        errors.push(Error {
+            line_num: None,
+            kind,
+            msg: with_code(None, first_line),
+            require_annotation: diagnostic.level != "failure-note"
+                && !RE.get_or_init(re_init).is_match(first_line),
+        });
+    } else {
+        for span in primary_spans {
+            errors.push(Error {
+                line_num: Some(span.line_start),
+                kind,
+                msg: with_code(Some(span), first_line),
+                require_annotation: true,
+            });
         }
     }
     for next_line in message_lines {
         if primary_spans.is_empty() {
-            expected_errors.push(Error {
+            errors.push(Error {
                 line_num: None,
-                kind: None,
+                kind,
                 msg: with_code(None, next_line),
+                require_annotation: false,
             });
         } else {
             for span in primary_spans {
-                expected_errors.push(Error {
+                errors.push(Error {
                     line_num: Some(span.line_start),
-                    kind: None,
+                    kind,
                     msg: with_code(Some(span), next_line),
+                    require_annotation: false,
                 });
             }
         }
@@ -283,10 +276,11 @@ fn push_expected_errors(
     for span in primary_spans {
         if let Some(ref suggested_replacement) = span.suggested_replacement {
             for (index, line) in suggested_replacement.lines().enumerate() {
-                expected_errors.push(Error {
+                errors.push(Error {
                     line_num: Some(span.line_start + index),
                     kind: Some(ErrorKind::Suggestion),
                     msg: line.to_string(),
+                    require_annotation: true,
                 });
             }
         }
@@ -295,39 +289,41 @@ fn push_expected_errors(
     // Add notes for the backtrace
     for span in primary_spans {
         if let Some(frame) = &span.expansion {
-            push_backtrace(expected_errors, frame, file_name);
+            push_backtrace(errors, frame, file_name);
         }
     }
 
     // Add notes for any labels that appear in the message.
     for span in spans_in_this_file.iter().filter(|span| span.label.is_some()) {
-        expected_errors.push(Error {
+        errors.push(Error {
             line_num: Some(span.line_start),
             kind: Some(ErrorKind::Note),
             msg: span.label.clone().unwrap(),
+            require_annotation: true,
         });
     }
 
     // Flatten out the children.
     for child in &diagnostic.children {
-        push_expected_errors(expected_errors, child, primary_spans, file_name);
+        push_actual_errors(errors, child, primary_spans, file_name);
     }
 }
 
 fn push_backtrace(
-    expected_errors: &mut Vec<Error>,
+    errors: &mut Vec<Error>,
     expansion: &DiagnosticSpanMacroExpansion,
     file_name: &str,
 ) {
     if Path::new(&expansion.span.file_name) == Path::new(&file_name) {
-        expected_errors.push(Error {
+        errors.push(Error {
             line_num: Some(expansion.span.line_start),
             kind: Some(ErrorKind::Note),
             msg: format!("in this expansion of {}", expansion.macro_decl_name),
+            require_annotation: true,
         });
     }
 
     if let Some(previous_expansion) = &expansion.span.expansion {
-        push_backtrace(expected_errors, previous_expansion, file_name);
+        push_backtrace(errors, previous_expansion, file_name);
     }
 }
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index 950566b2582..4bbd4ab4790 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -1,7 +1,8 @@
 #![crate_name = "compiletest"]
-// The `test` crate is the only unstable feature
-// allowed here, just to share similar code.
+// Needed by the libtest-based test executor.
 #![feature(test)]
+// Needed by the "new" test executor that does not depend on libtest.
+#![feature(internal_output_capture)]
 
 extern crate test;
 
@@ -12,6 +13,7 @@ pub mod common;
 pub mod compute_diff;
 mod debuggers;
 pub mod errors;
+mod executor;
 pub mod header;
 mod json;
 mod raise_fd_limit;
@@ -21,18 +23,16 @@ pub mod util;
 
 use core::panic;
 use std::collections::HashSet;
-use std::ffi::OsString;
 use std::fmt::Write;
 use std::io::{self, ErrorKind};
-use std::path::{Path, PathBuf};
 use std::process::{Command, Stdio};
 use std::sync::{Arc, OnceLock};
 use std::time::SystemTime;
 use std::{env, fs, vec};
 
 use build_helper::git::{get_git_modified_files, get_git_untracked_files};
+use camino::{Utf8Path, Utf8PathBuf};
 use getopts::Options;
-use test::ColorConfig;
 use tracing::*;
 use walkdir::WalkDir;
 
@@ -41,6 +41,7 @@ use crate::common::{
     CompareMode, Config, Debugger, Mode, PassMode, TestPaths, UI_EXTENSIONS, expected_output_path,
     output_base_dir, output_relative_path,
 };
+use crate::executor::{CollectedTest, ColorConfig, OutputFormat};
 use crate::header::HeadersCache;
 use crate::util::logv;
 
@@ -50,6 +51,12 @@ 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")
@@ -128,10 +135,10 @@ pub fn parse_config(args: Vec<String>) -> Config {
             "bless",
             "overwrite stderr/stdout files instead of complaining about a mismatch",
         )
+        .optflag("", "fail-fast", "stop as soon as possible after any test fails")
         .optflag("", "quiet", "print one character per test instead of one line")
         .optopt("", "color", "coloring: auto, always, never", "WHEN")
         .optflag("", "json", "emit json output instead of plaintext output")
-        .optopt("", "logfile", "file to log test execution to", "FILE")
         .optopt("", "target", "the target to build for", "TARGET")
         .optopt("", "host", "the host to build for", "HOST")
         .optopt("", "cdb", "path to CDB to use for CDB debuginfo tests", "PATH")
@@ -196,6 +203,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
             "COMMAND",
         )
         .reqopt("", "minicore-path", "path to minicore aux library", "PATH")
+        .optflag("n", "new-executor", "enables the new test executor instead of using libtest")
         .optopt(
             "",
             "debugger",
@@ -223,15 +231,19 @@ pub fn parse_config(args: Vec<String>) -> Config {
         panic!()
     }
 
-    fn opt_path(m: &getopts::Matches, nm: &str) -> PathBuf {
-        match m.opt_str(nm) {
-            Some(s) => PathBuf::from(&s),
-            None => panic!("no option (=path) found for {}", nm),
+    fn make_absolute(path: Utf8PathBuf) -> Utf8PathBuf {
+        if path.is_relative() {
+            Utf8PathBuf::try_from(env::current_dir().unwrap()).unwrap().join(path)
+        } else {
+            path
         }
     }
 
-    fn make_absolute(path: PathBuf) -> PathBuf {
-        if path.is_relative() { env::current_dir().unwrap().join(path) } else { path }
+    fn opt_path(m: &getopts::Matches, nm: &str) -> Utf8PathBuf {
+        match m.opt_str(nm) {
+            Some(s) => Utf8PathBuf::from(&s),
+            None => panic!("no option (=path) found for {}", nm),
+        }
     }
 
     let target = opt_str2(matches.opt_str("target"));
@@ -272,12 +284,12 @@ pub fn parse_config(args: Vec<String>) -> Config {
             .free
             .iter()
             .map(|f| {
-                let path = Path::new(f);
+                let path = Utf8Path::new(f);
                 let mut iter = path.iter().skip(1);
 
                 // We skip the test folder and check if the user passed `rmake.rs`.
                 if iter.next().is_some_and(|s| s == "rmake.rs") && iter.next().is_none() {
-                    path.parent().unwrap().to_str().unwrap().to_string()
+                    path.parent().unwrap().to_string()
                 } else {
                     f.to_string()
                 }
@@ -309,8 +321,8 @@ pub fn parse_config(args: Vec<String>) -> Config {
     assert!(
         src_test_suite_root.starts_with(&src_root),
         "`src-root` must be a parent of `src-test-suite-root`: `src-root`=`{}`, `src-test-suite-root` = `{}`",
-        src_root.display(),
-        src_test_suite_root.display()
+        src_root,
+        src_test_suite_root
     );
 
     let build_root = opt_path(matches, "build-root");
@@ -319,19 +331,22 @@ pub fn parse_config(args: Vec<String>) -> Config {
 
     Config {
         bless: matches.opt_present("bless"),
+        fail_fast: matches.opt_present("fail-fast")
+            || env::var_os("RUSTC_TEST_FAIL_FAST").is_some(),
+
         compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
         run_lib_path: make_absolute(opt_path(matches, "run-lib-path")),
         rustc_path: opt_path(matches, "rustc-path"),
-        cargo_path: matches.opt_str("cargo-path").map(PathBuf::from),
-        stage0_rustc_path: matches.opt_str("stage0-rustc-path").map(PathBuf::from),
-        rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from),
-        coverage_dump_path: matches.opt_str("coverage-dump-path").map(PathBuf::from),
+        cargo_path: matches.opt_str("cargo-path").map(Utf8PathBuf::from),
+        stage0_rustc_path: matches.opt_str("stage0-rustc-path").map(Utf8PathBuf::from),
+        rustdoc_path: matches.opt_str("rustdoc-path").map(Utf8PathBuf::from),
+        coverage_dump_path: matches.opt_str("coverage-dump-path").map(Utf8PathBuf::from),
         python: matches.opt_str("python").unwrap(),
         jsondocck_path: matches.opt_str("jsondocck-path"),
         jsondoclint_path: matches.opt_str("jsondoclint-path"),
         run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"),
-        llvm_filecheck: matches.opt_str("llvm-filecheck").map(PathBuf::from),
-        llvm_bin_dir: matches.opt_str("llvm-bin-dir").map(PathBuf::from),
+        llvm_filecheck: matches.opt_str("llvm-filecheck").map(Utf8PathBuf::from),
+        llvm_bin_dir: matches.opt_str("llvm-bin-dir").map(Utf8PathBuf::from),
 
         src_root,
         src_test_suite_root,
@@ -367,7 +382,6 @@ pub fn parse_config(args: Vec<String>) -> Config {
             "never" => Some(false),
             _ => panic!("unknown `--run` option `{}` given", mode),
         }),
-        logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)),
         runner: matches.opt_str("runner"),
         host_rustcflags: matches.opt_strs("host-rustcflags"),
         target_rustcflags: matches.opt_strs("target-rustcflags"),
@@ -392,13 +406,13 @@ pub fn parse_config(args: Vec<String>) -> Config {
         verbose: matches.opt_present("verbose"),
         format: match (matches.opt_present("quiet"), matches.opt_present("json")) {
             (true, true) => panic!("--quiet and --json are incompatible"),
-            (true, false) => test::OutputFormat::Terse,
-            (false, true) => test::OutputFormat::Json,
-            (false, false) => test::OutputFormat::Pretty,
+            (true, false) => OutputFormat::Terse,
+            (false, true) => OutputFormat::Json,
+            (false, false) => OutputFormat::Pretty,
         },
         only_modified: matches.opt_present("only-modified"),
         color,
-        remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from),
+        remote_test_client: matches.opt_str("remote-test-client").map(Utf8PathBuf::from),
         compare_mode,
         rustfix_coverage: matches.opt_present("rustfix-coverage"),
         has_html_tidy,
@@ -422,6 +436,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
 
         target_cfgs: OnceLock::new(),
         builtin_cfg_names: OnceLock::new(),
+        supported_crate_types: OnceLock::new(),
 
         nocapture: matches.opt_present("no-capture"),
 
@@ -434,25 +449,27 @@ pub fn parse_config(args: Vec<String>) -> Config {
         diff_command: matches.opt_str("compiletest-diff-tool"),
 
         minicore_path: opt_path(matches, "minicore-path"),
+
+        new_executor: matches.opt_present("new-executor"),
     }
 }
 
 pub fn log_config(config: &Config) {
     let c = config;
     logv(c, "configuration:".to_string());
-    logv(c, format!("compile_lib_path: {:?}", config.compile_lib_path));
-    logv(c, format!("run_lib_path: {:?}", config.run_lib_path));
-    logv(c, format!("rustc_path: {:?}", config.rustc_path.display()));
+    logv(c, format!("compile_lib_path: {}", config.compile_lib_path));
+    logv(c, format!("run_lib_path: {}", config.run_lib_path));
+    logv(c, format!("rustc_path: {}", config.rustc_path));
     logv(c, format!("cargo_path: {:?}", config.cargo_path));
     logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path));
 
-    logv(c, format!("src_root: {}", config.src_root.display()));
-    logv(c, format!("src_test_suite_root: {}", config.src_test_suite_root.display()));
+    logv(c, format!("src_root: {}", config.src_root));
+    logv(c, format!("src_test_suite_root: {}", config.src_test_suite_root));
 
-    logv(c, format!("build_root: {}", config.build_root.display()));
-    logv(c, format!("build_test_suite_root: {}", config.build_test_suite_root.display()));
+    logv(c, format!("build_root: {}", config.build_root));
+    logv(c, format!("build_test_suite_root: {}", config.build_test_suite_root));
 
-    logv(c, format!("sysroot_base: {}", config.sysroot_base.display()));
+    logv(c, format!("sysroot_base: {}", config.sysroot_base));
 
     logv(c, format!("stage: {}", config.stage));
     logv(c, format!("stage_id: {}", config.stage_id));
@@ -470,16 +487,16 @@ pub fn log_config(config: &Config) {
     logv(c, format!("target-rustcflags: {:?}", config.target_rustcflags));
     logv(c, format!("target: {}", config.target));
     logv(c, format!("host: {}", config.host));
-    logv(c, format!("android-cross-path: {:?}", config.android_cross_path.display()));
-    logv(c, format!("adb_path: {:?}", config.adb_path));
-    logv(c, format!("adb_test_dir: {:?}", config.adb_test_dir));
+    logv(c, format!("android-cross-path: {}", config.android_cross_path));
+    logv(c, format!("adb_path: {}", config.adb_path));
+    logv(c, format!("adb_test_dir: {}", config.adb_test_dir));
     logv(c, format!("adb_device_status: {}", config.adb_device_status));
     logv(c, format!("ar: {}", config.ar));
     logv(c, format!("target-linker: {:?}", config.target_linker));
     logv(c, format!("host-linker: {:?}", config.host_linker));
     logv(c, format!("verbose: {}", config.verbose));
     logv(c, format!("format: {:?}", config.format));
-    logv(c, format!("minicore_path: {:?}", config.minicore_path.display()));
+    logv(c, format!("minicore_path: {}", config.minicore_path));
     logv(c, "\n".to_string());
 }
 
@@ -507,7 +524,7 @@ pub fn run_tests(config: Arc<Config>) {
         coverage_file_path.push("rustfix_missing_coverage.txt");
         if coverage_file_path.exists() {
             if let Err(e) = fs::remove_file(&coverage_file_path) {
-                panic!("Could not delete {} due to {}", coverage_file_path.display(), e)
+                panic!("Could not delete {} due to {}", coverage_file_path, e)
             }
         }
     }
@@ -520,12 +537,14 @@ pub fn run_tests(config: Arc<Config>) {
     }
     // Prevent issue #21352 UAC blocking .exe containing 'patch' etc. on Windows
     // If #11207 is resolved (adding manifest to .exe) this becomes unnecessary
-    env::set_var("__COMPAT_LAYER", "RunAsInvoker");
-
-    // Let tests know which target they're running as
-    env::set_var("TARGET", &config.target);
+    //
+    // SAFETY: at this point we're still single-threaded.
+    unsafe { env::set_var("__COMPAT_LAYER", "RunAsInvoker") };
 
-    let opts = test_opts(&config);
+    // Let tests know which target they're running as.
+    //
+    // SAFETY: at this point we're still single-threaded.
+    unsafe { env::set_var("TARGET", &config.target) };
 
     let mut configs = Vec::new();
     if let Mode::DebugInfo = config.mode {
@@ -553,12 +572,16 @@ pub fn run_tests(config: Arc<Config>) {
         tests.extend(collect_and_make_tests(c));
     }
 
-    tests.sort_by(|a, b| a.desc.name.as_slice().cmp(&b.desc.name.as_slice()));
+    tests.sort_by(|a, b| Ord::cmp(&a.desc.name, &b.desc.name));
 
-    // Delegate to libtest to filter and run the big list of structures created
-    // during test discovery. When libtest decides to run a test, it will invoke
-    // the corresponding closure created by `make_test_closure`.
-    let res = test::run_tests_console(&opts, tests);
+    // Delegate to the executor to filter and run the big list of test structures
+    // created during test discovery. When the executor decides to run a test,
+    // it will return control to the rest of compiletest by calling `runtest::run`.
+    let res = if config.new_executor {
+        Ok(executor::run_tests(&config, tests))
+    } else {
+        crate::executor::libtest::execute_tests(&config, tests)
+    };
 
     // Check the outcome reported by libtest.
     match res {
@@ -602,66 +625,34 @@ pub fn run_tests(config: Arc<Config>) {
     }
 }
 
-pub fn test_opts(config: &Config) -> test::TestOpts {
-    if env::var("RUST_TEST_NOCAPTURE").is_ok() {
-        eprintln!(
-            "WARNING: RUST_TEST_NOCAPTURE is no longer used. \
-                   Use the `--nocapture` flag instead."
-        );
-    }
-
-    test::TestOpts {
-        exclude_should_panic: false,
-        filters: config.filters.clone(),
-        filter_exact: config.filter_exact,
-        run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No },
-        format: config.format,
-        logfile: config.logfile.clone(),
-        run_tests: true,
-        bench_benchmarks: true,
-        nocapture: config.nocapture,
-        color: config.color,
-        shuffle: false,
-        shuffle_seed: None,
-        test_threads: None,
-        skip: config.skip.clone(),
-        list: false,
-        options: test::Options::new(),
-        time_options: None,
-        force_run_in_process: false,
-        fail_fast: std::env::var_os("RUSTC_TEST_FAIL_FAST").is_some(),
-    }
-}
-
 /// Read-only context data used during test collection.
 struct TestCollectorCx {
     config: Arc<Config>,
     cache: HeadersCache,
     common_inputs_stamp: Stamp,
-    modified_tests: Vec<PathBuf>,
+    modified_tests: Vec<Utf8PathBuf>,
 }
 
 /// Mutable state used during test collection.
 struct TestCollector {
-    tests: Vec<test::TestDescAndFn>,
-    found_path_stems: HashSet<PathBuf>,
+    tests: Vec<CollectedTest>,
+    found_path_stems: HashSet<Utf8PathBuf>,
     poisoned: bool,
 }
 
-/// Creates libtest structures for every test/revision in the test suite directory.
+/// Creates test structures for every test/revision in the test suite directory.
 ///
 /// This always inspects _all_ test files in the suite (e.g. all 17k+ ui tests),
 /// regardless of whether any filters/tests were specified on the command-line,
 /// because filtering is handled later by libtest.
-pub fn collect_and_make_tests(config: Arc<Config>) -> Vec<test::TestDescAndFn> {
-    debug!("making tests from {}", config.src_test_suite_root.display());
+pub(crate) fn collect_and_make_tests(config: Arc<Config>) -> Vec<CollectedTest> {
+    debug!("making tests from {}", config.src_test_suite_root);
     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.display(),
-                err
+                config.src_test_suite_root, err
             )
         });
     let cache = HeadersCache::load(&config);
@@ -670,12 +661,9 @@ pub fn collect_and_make_tests(config: Arc<Config>) -> Vec<test::TestDescAndFn> {
     let mut collector =
         TestCollector { tests: vec![], found_path_stems: HashSet::new(), poisoned: false };
 
-    collect_tests_from_dir(&cx, &mut collector, &cx.config.src_test_suite_root, Path::new(""))
+    collect_tests_from_dir(&cx, &mut collector, &cx.config.src_test_suite_root, Utf8Path::new(""))
         .unwrap_or_else(|reason| {
-            panic!(
-                "Could not read tests from {}: {reason}",
-                cx.config.src_test_suite_root.display()
-            )
+            panic!("Could not read tests from {}: {reason}", cx.config.src_test_suite_root)
         });
 
     let TestCollector { tests, found_path_stems, poisoned } = collector;
@@ -744,24 +732,29 @@ fn common_inputs_stamp(config: &Config) -> Stamp {
 /// the `--only-modified` flag is in use.
 ///
 /// (Might be inaccurate in some cases.)
-fn modified_tests(config: &Config, dir: &Path) -> Result<Vec<PathBuf>, String> {
+fn modified_tests(config: &Config, dir: &Utf8Path) -> Result<Vec<Utf8PathBuf>, String> {
     // If `--only-modified` wasn't passed, the list of modified tests won't be
     // used for anything, so avoid some work and just return an empty list.
     if !config.only_modified {
         return Ok(vec![]);
     }
 
-    let files =
-        get_git_modified_files(&config.git_config(), Some(dir), &vec!["rs", "stderr", "fixed"])?;
+    let files = get_git_modified_files(
+        &config.git_config(),
+        Some(dir.as_std_path()),
+        &vec!["rs", "stderr", "fixed"],
+    )?;
     // Add new test cases to the list, it will be convenient in daily development.
     let untracked_files = get_git_untracked_files(&config.git_config(), None)?.unwrap_or(vec![]);
 
     let all_paths = [&files[..], &untracked_files[..]].concat();
     let full_paths = {
-        let mut full_paths: Vec<PathBuf> = all_paths
+        let mut full_paths: Vec<Utf8PathBuf> = all_paths
             .into_iter()
-            .map(|f| PathBuf::from(f).with_extension("").with_extension("rs"))
-            .filter_map(|f| if Path::new(&f).exists() { f.canonicalize().ok() } else { None })
+            .map(|f| Utf8PathBuf::from(f).with_extension("").with_extension("rs"))
+            .filter_map(
+                |f| if Utf8Path::new(&f).exists() { f.canonicalize_utf8().ok() } else { None },
+            )
             .collect();
         full_paths.dedup();
         full_paths.sort_unstable();
@@ -775,8 +768,8 @@ fn modified_tests(config: &Config, dir: &Path) -> Result<Vec<PathBuf>, String> {
 fn collect_tests_from_dir(
     cx: &TestCollectorCx,
     collector: &mut TestCollector,
-    dir: &Path,
-    relative_dir_path: &Path,
+    dir: &Utf8Path,
+    relative_dir_path: &Utf8Path,
 ) -> io::Result<()> {
     // Ignore directories that contain a file named `compiletest-ignore-dir`.
     if dir.join("compiletest-ignore-dir").exists() {
@@ -809,16 +802,16 @@ fn collect_tests_from_dir(
     // subdirectories we find, except for `auxiliary` directories.
     // FIXME: this walks full tests tree, even if we have something to ignore
     // use walkdir/ignore like in tidy?
-    for file in fs::read_dir(dir)? {
+    for file in fs::read_dir(dir.as_std_path())? {
         let file = file?;
-        let file_path = file.path();
-        let file_name = file.file_name();
+        let file_path = Utf8PathBuf::try_from(file.path()).unwrap();
+        let file_name = file_path.file_name().unwrap();
 
-        if is_test(&file_name)
+        if is_test(file_name)
             && (!cx.config.only_modified || cx.modified_tests.contains(&file_path))
         {
             // We found a test file, so create the corresponding libtest structures.
-            debug!("found test file: {:?}", file_path.display());
+            debug!(%file_path, "found test file");
 
             // Record the stem of the test file, to check for overlaps later.
             let rel_test_path = relative_dir_path.join(file_path.file_stem().unwrap());
@@ -829,22 +822,20 @@ fn collect_tests_from_dir(
             make_test(cx, collector, &paths);
         } else if file_path.is_dir() {
             // Recurse to find more tests in a subdirectory.
-            let relative_file_path = relative_dir_path.join(file.file_name());
-            if &file_name != "auxiliary" {
-                debug!("found directory: {:?}", file_path.display());
+            let relative_file_path = relative_dir_path.join(file_name);
+            if file_name != "auxiliary" {
+                debug!(%file_path, "found directory");
                 collect_tests_from_dir(cx, collector, &file_path, &relative_file_path)?;
             }
         } else {
-            debug!("found other file/directory: {:?}", file_path.display());
+            debug!(%file_path, "found other file/directory");
         }
     }
     Ok(())
 }
 
 /// Returns true if `file_name` looks like a proper test file name.
-pub fn is_test(file_name: &OsString) -> bool {
-    let file_name = file_name.to_str().unwrap();
-
+pub fn is_test(file_name: &str) -> bool {
     if !file_name.ends_with(".rs") {
         return false;
     }
@@ -863,7 +854,7 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te
     let test_path = if cx.config.mode == Mode::RunMake {
         testpaths.file.join("rmake.rs")
     } else {
-        PathBuf::from(&testpaths.file)
+        testpaths.file.clone()
     };
 
     // Scan the test file to discover its revisions, if any.
@@ -882,7 +873,7 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te
     };
 
     // For each revision (or the sole dummy revision), create and append a
-    // `test::TestDescAndFn` that can be handed over to libtest.
+    // `CollectedTest` that can be handed over to the test executor.
     collector.tests.extend(revisions.into_iter().map(|revision| {
         // Create a test name and description to hand over to libtest.
         let src_file = fs::File::open(&test_path).expect("open test file to parse ignores");
@@ -905,19 +896,20 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te
         if !cx.config.force_rerun && is_up_to_date(cx, testpaths, &early_props, revision) {
             desc.ignore = true;
             // Keep this in sync with the "up-to-date" message detected by bootstrap.
-            desc.ignore_message = Some("up-to-date");
+            desc.ignore_message = Some("up-to-date".into());
         }
 
-        // Create the callback that will run this test/revision when libtest calls it.
-        let testfn = make_test_closure(Arc::clone(&cx.config), testpaths, revision);
+        let config = Arc::clone(&cx.config);
+        let testpaths = testpaths.clone();
+        let revision = revision.map(str::to_owned);
 
-        test::TestDescAndFn { desc, testfn }
+        CollectedTest { desc, config, testpaths, revision }
     }));
 }
 
 /// The path of the `stamp` file that gets created or updated whenever a
 /// particular test completes successfully.
-fn stamp_file_path(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
+fn stamp_file_path(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> Utf8PathBuf {
     output_base_dir(config, testpaths, revision).join("stamp")
 }
 
@@ -930,7 +922,7 @@ fn files_related_to_test(
     testpaths: &TestPaths,
     props: &EarlyProps,
     revision: Option<&str>,
-) -> Vec<PathBuf> {
+) -> Vec<Utf8PathBuf> {
     let mut related = vec![];
 
     if testpaths.file.is_dir() {
@@ -938,7 +930,7 @@ fn files_related_to_test(
         for entry in WalkDir::new(&testpaths.file) {
             let path = entry.unwrap().into_path();
             if path.is_file() {
-                related.push(path);
+                related.push(Utf8PathBuf::try_from(path).unwrap());
             }
         }
     } else {
@@ -1009,7 +1001,7 @@ struct Stamp {
 
 impl Stamp {
     /// Creates a timestamp holding the last-modified time of the specified file.
-    fn from_path(path: &Path) -> Self {
+    fn from_path(path: &Utf8Path) -> Self {
         let mut stamp = Stamp { time: SystemTime::UNIX_EPOCH };
         stamp.add_path(path);
         stamp
@@ -1017,8 +1009,8 @@ impl Stamp {
 
     /// Updates this timestamp to the last-modified time of the specified file,
     /// if it is later than the currently-stored timestamp.
-    fn add_path(&mut self, path: &Path) {
-        let modified = fs::metadata(path)
+    fn add_path(&mut self, path: &Utf8Path) {
+        let modified = fs::metadata(path.as_std_path())
             .and_then(|metadata| metadata.modified())
             .unwrap_or(SystemTime::UNIX_EPOCH);
         self.time = self.time.max(modified);
@@ -1027,7 +1019,8 @@ impl Stamp {
     /// Updates this timestamp to the most recent last-modified time of all files
     /// recursively contained in the given directory, if it is later than the
     /// currently-stored timestamp.
-    fn add_dir(&mut self, path: &Path) {
+    fn add_dir(&mut self, path: &Utf8Path) {
+        let path = path.as_std_path();
         for entry in WalkDir::new(path) {
             let entry = entry.unwrap();
             if entry.file_type().is_file() {
@@ -1043,11 +1036,7 @@ impl Stamp {
 }
 
 /// Creates a name for this test/revision that can be handed over to libtest.
-fn make_test_name(
-    config: &Config,
-    testpaths: &TestPaths,
-    revision: Option<&str>,
-) -> test::TestName {
+fn make_test_name(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> String {
     // Print the name of the file, relative to the sources root.
     let path = testpaths.file.strip_prefix(&config.src_root).unwrap();
     let debugger = match config.debugger {
@@ -1059,32 +1048,14 @@ fn make_test_name(
         None => String::new(),
     };
 
-    test::DynTestName(format!(
+    format!(
         "[{}{}{}] {}{}",
         config.mode,
         debugger,
         mode_suffix,
-        path.display(),
+        path,
         revision.map_or("".to_string(), |rev| format!("#{}", rev))
-    ))
-}
-
-/// Creates a callback for this test/revision that libtest will call when it
-/// decides to actually run the underlying test.
-fn make_test_closure(
-    config: Arc<Config>,
-    testpaths: &TestPaths,
-    revision: Option<&str>,
-) -> test::TestFn {
-    let testpaths = testpaths.clone();
-    let revision = revision.map(str::to_owned);
-
-    // This callback is the link between compiletest's test discovery code,
-    // and the parts of compiletest that know how to run an individual test.
-    test::DynTestFn(Box::new(move || {
-        runtest::run(config, &testpaths, revision.as_deref());
-        Ok(())
-    }))
+    )
 }
 
 /// Checks that test discovery didn't find any tests whose name stem is a prefix
@@ -1104,7 +1075,7 @@ fn make_test_closure(
 /// To avoid problems, we forbid test names from overlapping in this way.
 ///
 /// See <https://github.com/rust-lang/rust/pull/109509> for more context.
-fn check_for_overlapping_test_paths(found_path_stems: &HashSet<PathBuf>) {
+fn check_for_overlapping_test_paths(found_path_stems: &HashSet<Utf8PathBuf>) {
     let mut collisions = Vec::new();
     for path in found_path_stems {
         for ancestor in path.ancestors().skip(1) {
@@ -1117,7 +1088,7 @@ fn check_for_overlapping_test_paths(found_path_stems: &HashSet<PathBuf>) {
         collisions.sort();
         let collisions: String = collisions
             .into_iter()
-            .map(|(path, check_parent)| format!("test {path:?} clashes with {check_parent:?}\n"))
+            .map(|(path, check_parent)| format!("test {path} clashes with {check_parent}\n"))
             .collect();
         panic!(
             "{collisions}\n\
diff --git a/src/tools/compiletest/src/raise_fd_limit.rs b/src/tools/compiletest/src/raise_fd_limit.rs
index 7b12ba946b9..653b125a6b4 100644
--- a/src/tools/compiletest/src/raise_fd_limit.rs
+++ b/src/tools/compiletest/src/raise_fd_limit.rs
@@ -6,6 +6,7 @@
 /// This fixes issue #7772.
 #[cfg(target_vendor = "apple")]
 #[allow(non_camel_case_types)]
+// FIXME(#139616): document caller contract.
 pub unsafe fn raise_fd_limit() {
     use std::ptr::null_mut;
     use std::{cmp, io};
@@ -21,8 +22,10 @@ pub unsafe fn raise_fd_limit() {
     let mut mib: [libc::c_int; 2] = [CTL_KERN, KERN_MAXFILESPERPROC];
     let mut maxfiles: libc::c_int = 0;
     let mut size: libc::size_t = size_of_val(&maxfiles) as libc::size_t;
-    if libc::sysctl(&mut mib[0], 2, &mut maxfiles as *mut _ as *mut _, &mut size, null_mut(), 0)
-        != 0
+    // FIXME(#139616): justify why this is sound.
+    if unsafe {
+        libc::sysctl(&mut mib[0], 2, &mut maxfiles as *mut _ as *mut _, &mut size, null_mut(), 0)
+    } != 0
     {
         let err = io::Error::last_os_error();
         panic!("raise_fd_limit: error calling sysctl: {}", err);
@@ -30,7 +33,8 @@ pub unsafe fn raise_fd_limit() {
 
     // Fetch the current resource limits
     let mut rlim = libc::rlimit { rlim_cur: 0, rlim_max: 0 };
-    if libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) != 0 {
+    // FIXME(#139616): justify why this is sound.
+    if unsafe { libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) } != 0 {
         let err = io::Error::last_os_error();
         panic!("raise_fd_limit: error calling getrlimit: {}", err);
     }
@@ -41,7 +45,8 @@ pub unsafe fn raise_fd_limit() {
         rlim.rlim_cur = cmp::min(maxfiles as libc::rlim_t, rlim.rlim_max);
 
         // Set our newly-increased resource limit.
-        if libc::setrlimit(libc::RLIMIT_NOFILE, &rlim) != 0 {
+        // FIXME(#139616): justify why this is sound.
+        if unsafe { libc::setrlimit(libc::RLIMIT_NOFILE, &rlim) } != 0 {
             let err = io::Error::last_os_error();
             panic!("raise_fd_limit: error calling setrlimit: {}", err);
         }
diff --git a/src/tools/compiletest/src/read2.rs b/src/tools/compiletest/src/read2.rs
index 28ca5589992..2213dd07160 100644
--- a/src/tools/compiletest/src/read2.rs
+++ b/src/tools/compiletest/src/read2.rs
@@ -165,6 +165,7 @@ mod imp {
         mut err_pipe: ChildStderr,
         data: &mut dyn FnMut(bool, &mut Vec<u8>, bool),
     ) -> io::Result<()> {
+        // FIXME(#139616): justify why this is sound.
         unsafe {
             libc::fcntl(out_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK);
             libc::fcntl(err_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK);
@@ -175,6 +176,7 @@ mod imp {
         let mut out = Vec::new();
         let mut err = Vec::new();
 
+        // FIXME(#139616): justify why this is sound.
         let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() };
         fds[0].fd = out_pipe.as_raw_fd();
         fds[0].events = libc::POLLIN;
@@ -185,6 +187,7 @@ mod imp {
 
         while nfds > 0 {
             // wait for either pipe to become readable using `select`
+            // FIXME(#139616): justify why this is sound.
             let r = unsafe { libc::poll(fds.as_mut_ptr(), nfds, -1) };
             if r == -1 {
                 let err = io::Error::last_os_error();
@@ -256,6 +259,7 @@ mod imp {
         port.add_handle(0, &out_pipe)?;
         port.add_handle(1, &err_pipe)?;
 
+        // FIXME(#139616): justify why this is sound.
         unsafe {
             let mut out_pipe = Pipe::new(out_pipe, &mut out);
             let mut err_pipe = Pipe::new(err_pipe, &mut err);
@@ -284,18 +288,23 @@ mod imp {
     }
 
     impl<'a> Pipe<'a> {
+        // FIXME(#139616): document caller contract.
         unsafe fn new<P: IntoRawHandle>(p: P, dst: &'a mut Vec<u8>) -> Pipe<'a> {
             Pipe {
                 dst,
-                pipe: NamedPipe::from_raw_handle(p.into_raw_handle()),
+                // FIXME(#139616): justify why this is sound.
+                pipe: unsafe { NamedPipe::from_raw_handle(p.into_raw_handle()) },
                 overlapped: Overlapped::zero(),
                 done: false,
             }
         }
 
+        // FIXME(#139616): document caller contract.
         unsafe fn read(&mut self) -> io::Result<()> {
-            let dst = slice_to_end(self.dst);
-            match self.pipe.read_overlapped(dst, self.overlapped.raw()) {
+            // FIXME(#139616): justify why this is sound.
+            let dst = unsafe { slice_to_end(self.dst) };
+            // FIXME(#139616): justify why this is sound.
+            match unsafe { self.pipe.read_overlapped(dst, self.overlapped.raw()) } {
                 Ok(_) => Ok(()),
                 Err(e) => {
                     if e.raw_os_error() == Some(ERROR_BROKEN_PIPE.0 as i32) {
@@ -308,15 +317,18 @@ mod imp {
             }
         }
 
+        // FIXME(#139616): document caller contract.
         unsafe fn complete(&mut self, status: &CompletionStatus) {
             let prev = self.dst.len();
-            self.dst.set_len(prev + status.bytes_transferred() as usize);
+            // FIXME(#139616): justify why this is sound.
+            unsafe { self.dst.set_len(prev + status.bytes_transferred() as usize) };
             if status.bytes_transferred() == 0 {
                 self.done = true;
             }
         }
     }
 
+    // FIXME(#139616): document caller contract.
     unsafe fn slice_to_end(v: &mut Vec<u8>) -> &mut [u8] {
         if v.capacity() == 0 {
             v.reserve(16);
@@ -324,6 +336,12 @@ mod imp {
         if v.capacity() == v.len() {
             v.reserve(1);
         }
-        slice::from_raw_parts_mut(v.as_mut_ptr().offset(v.len() as isize), v.capacity() - v.len())
+        // FIXME(#139616): justify why this is sound.
+        unsafe {
+            slice::from_raw_parts_mut(
+                v.as_mut_ptr().offset(v.len() as isize),
+                v.capacity() - v.len(),
+            )
+        }
     }
 }
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index c8a60b68da8..eb298060b2e 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1,16 +1,15 @@
 use std::borrow::Cow;
 use std::collections::{HashMap, HashSet};
-use std::ffi::{OsStr, OsString};
+use std::ffi::OsString;
 use std::fs::{self, File, create_dir_all};
 use std::hash::{DefaultHasher, Hash, Hasher};
 use std::io::prelude::*;
 use std::io::{self, BufReader};
-use std::path::{Path, PathBuf};
 use std::process::{Child, Command, ExitStatus, Output, Stdio};
 use std::sync::Arc;
 use std::{env, iter, str};
 
-use anyhow::Context;
+use camino::{Utf8Path, Utf8PathBuf};
 use colored::Colorize;
 use regex::{Captures, Regex};
 use tracing::*;
@@ -23,10 +22,10 @@ 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::errors::{self, Error, ErrorKind};
+use crate::errors::{Error, ErrorKind};
 use crate::header::TestProps;
 use crate::read2::{Truncated, read2_abbreviated};
-use crate::util::{PathBufExt, add_dylib_path, logv, static_regex};
+use crate::util::{Utf8PathBufExt, add_dylib_path, logv, static_regex};
 use crate::{ColorConfig, json, stamp_file_path};
 
 mod debugger;
@@ -132,7 +131,7 @@ pub fn run(config: Arc<Config>, testpaths: &TestPaths, revision: Option<&str>) {
         // We're going to be dumping a lot of info. Start on a new line.
         print!("\n\n");
     }
-    debug!("running {:?}", testpaths.file.display());
+    debug!("running {}", testpaths.file);
     let mut props = TestProps::from_file(&testpaths.file, revision, &config);
 
     // For non-incremental (i.e. regular UI) tests, the incremental directory
@@ -143,11 +142,11 @@ pub fn run(config: Arc<Config>, testpaths: &TestPaths, revision: Option<&str>) {
     }
 
     let cx = TestCx { config: &config, props: &props, testpaths, revision };
-    create_dir_all(&cx.output_base_dir())
-        .with_context(|| {
-            format!("failed to create output base directory {}", cx.output_base_dir().display())
-        })
-        .unwrap();
+
+    if let Err(e) = create_dir_all(&cx.output_base_dir()) {
+        panic!("failed to create output base directory {}: {e}", cx.output_base_dir());
+    }
+
     if props.incremental {
         cx.init_incremental_test();
     }
@@ -178,6 +177,7 @@ pub fn compute_stamp_hash(config: &Config) -> String {
     let mut hash = DefaultHasher::new();
     config.stage_id.hash(&mut hash);
     config.run.hash(&mut hash);
+    config.edition.hash(&mut hash);
 
     match config.debugger {
         Some(Debugger::Cdb) => {
@@ -207,7 +207,8 @@ pub fn compute_stamp_hash(config: &Config) -> String {
     format!("{:x}", hash.finish())
 }
 
-fn remove_and_create_dir_all(path: &Path) {
+fn remove_and_create_dir_all(path: &Utf8Path) {
+    let path = path.as_std_path();
     let _ = fs::remove_dir_all(path);
     fs::create_dir_all(path).unwrap();
 }
@@ -423,7 +424,7 @@ impl<'test> TestCx<'test> {
         let aux_dir = self.aux_output_dir_name();
         let input: &str = match read_from {
             ReadFrom::Stdin(_) => "-",
-            ReadFrom::Path => self.testpaths.file.to_str().unwrap(),
+            ReadFrom::Path => self.testpaths.file.as_str(),
         };
 
         let mut rustc = Command::new(&self.config.rustc_path);
@@ -446,8 +447,8 @@ impl<'test> TestCx<'test> {
 
         self.compose_and_run(
             rustc,
-            self.config.compile_lib_path.to_str().unwrap(),
-            Some(aux_dir.to_str().unwrap()),
+            self.config.compile_lib_path.as_path(),
+            Some(aux_dir.as_path()),
             src,
         )
     }
@@ -590,10 +591,7 @@ impl<'test> TestCx<'test> {
                 // FIXME(#65865)
                 return;
             } else {
-                self.fatal(&format!(
-                    "no error pattern specified in {:?}",
-                    self.testpaths.file.display()
-                ));
+                self.fatal(&format!("no error pattern specified in {}", self.testpaths.file));
             }
         }
 
@@ -675,7 +673,7 @@ impl<'test> TestCx<'test> {
         }
     }
 
-    fn check_expected_errors(&self, expected_errors: Vec<errors::Error>, proc_res: &ProcRes) {
+    fn check_expected_errors(&self, expected_errors: Vec<Error>, proc_res: &ProcRes) {
         debug!(
             "check_expected_errors: expected_errors={:?} proc_res.status={:?}",
             expected_errors, proc_res.status
@@ -697,25 +695,25 @@ impl<'test> TestCx<'test> {
         }
 
         // On Windows, translate all '\' path separators to '/'
-        let file_name = format!("{}", self.testpaths.file.display()).replace(r"\", "/");
+        let file_name = self.testpaths.file.to_string().replace(r"\", "/");
 
         // On Windows, keep all '\' path separators to match the paths reported in the JSON output
         // from the compiler
         let diagnostic_file_name = if self.props.remap_src_base {
-            let mut p = PathBuf::from(FAKE_SRC_BASE);
+            let mut p = Utf8PathBuf::from(FAKE_SRC_BASE);
             p.push(&self.testpaths.relative_dir);
             p.push(self.testpaths.file.file_name().unwrap());
-            p.display().to_string()
+            p.to_string()
         } else {
-            self.testpaths.file.display().to_string()
+            self.testpaths.file.to_string()
         };
 
-        // If the testcase being checked contains at least one expected "help"
-        // message, then we'll ensure that all "help" messages are expected.
-        // Otherwise, all "help" messages reported by the compiler will be ignored.
-        // This logic also applies to "note" messages.
-        let expect_help = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Help));
-        let expect_note = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Note));
+        // Errors and warnings are always expected, other diagnostics are only expected
+        // if one of them actually occurs in the test.
+        let expected_kinds: HashSet<_> = [ErrorKind::Error, ErrorKind::Warning]
+            .into_iter()
+            .chain(expected_errors.iter().filter_map(|e| e.kind))
+            .collect();
 
         // Parse the JSON output from the compiler and extract out the messages.
         let actual_errors = json::parse_output(&diagnostic_file_name, &proc_res.stderr, proc_res);
@@ -741,8 +739,11 @@ impl<'test> TestCx<'test> {
                 }
 
                 None => {
-                    // If the test is a known bug, don't require that the error is annotated
-                    if self.is_unexpected_compiler_message(&actual_error, expect_help, expect_note)
+                    if actual_error.require_annotation
+                        && actual_error.kind.map_or(false, |kind| {
+                            expected_kinds.contains(&kind)
+                                && !self.props.dont_require_annotations.contains(&kind)
+                        })
                     {
                         self.error(&format!(
                             "{}:{}: unexpected {}: '{}'",
@@ -800,25 +801,6 @@ impl<'test> TestCx<'test> {
         }
     }
 
-    /// Returns `true` if we should report an error about `actual_error`,
-    /// which did not match any of the expected error. We always require
-    /// errors/warnings to be explicitly listed, but only require
-    /// helps/notes if there are explicit helps/notes given.
-    fn is_unexpected_compiler_message(
-        &self,
-        actual_error: &Error,
-        expect_help: bool,
-        expect_note: bool,
-    ) -> bool {
-        !actual_error.msg.is_empty()
-            && match actual_error.kind {
-                Some(ErrorKind::Help) => expect_help,
-                Some(ErrorKind::Note) => expect_note,
-                Some(ErrorKind::Error) | Some(ErrorKind::Warning) => true,
-                Some(ErrorKind::Suggestion) | None => false,
-            }
-    }
-
     fn should_emit_metadata(&self, pm: Option<PassMode>) -> Emit {
         match (pm, self.props.fail_mode, self.config.mode) {
             (Some(PassMode::Check), ..) | (_, Some(FailMode::Check), Ui) => Emit::Metadata,
@@ -889,7 +871,7 @@ impl<'test> TestCx<'test> {
 
     /// `root_out_dir` and `root_testpaths` refer to the parameters of the actual test being run.
     /// Auxiliaries, no matter how deep, have the same root_out_dir and root_testpaths.
-    fn document(&self, root_out_dir: &Path, root_testpaths: &TestPaths) -> ProcRes {
+    fn document(&self, root_out_dir: &Utf8Path, root_testpaths: &TestPaths) -> ProcRes {
         if self.props.build_aux_docs {
             for rel_ab in &self.props.aux.builds {
                 let aux_testpaths = self.compute_aux_test_paths(root_testpaths, rel_ab);
@@ -918,13 +900,13 @@ impl<'test> TestCx<'test> {
 
         // actual --out-dir given to the auxiliary or test, as opposed to the root out dir for the entire
         // test
-        let out_dir: Cow<'_, Path> = if self.props.unique_doc_out_dir {
+        let out_dir: Cow<'_, Utf8Path> = if self.props.unique_doc_out_dir {
             let file_name = self.testpaths.file.file_stem().expect("file name should not be empty");
-            let out_dir = PathBuf::from_iter([
+            let out_dir = Utf8PathBuf::from_iter([
                 root_out_dir,
-                Path::new("docs"),
-                Path::new(file_name),
-                Path::new("doc"),
+                Utf8Path::new("docs"),
+                Utf8Path::new(file_name),
+                Utf8Path::new("doc"),
             ]);
             create_dir_all(&out_dir).unwrap();
             Cow::Owned(out_dir)
@@ -937,7 +919,7 @@ impl<'test> TestCx<'test> {
         rustdoc.current_dir(current_dir);
         rustdoc
             .arg("-L")
-            .arg(self.config.run_lib_path.to_str().unwrap())
+            .arg(self.config.run_lib_path.as_path())
             .arg("-L")
             .arg(aux_dir)
             .arg("-o")
@@ -971,16 +953,16 @@ impl<'test> TestCx<'test> {
         delete_after_success: bool,
     ) -> ProcRes {
         let prepare_env = |cmd: &mut Command| {
-            for key in &self.props.unset_exec_env {
-                cmd.env_remove(key);
-            }
-
             for (key, val) in &self.props.exec_env {
                 cmd.env(key, val);
             }
             for (key, val) in env_extra {
                 cmd.env(key, val);
             }
+
+            for key in &self.props.unset_exec_env {
+                cmd.env_remove(key);
+            }
         };
 
         let proc_res = match &*self.config.target {
@@ -1023,8 +1005,8 @@ impl<'test> TestCx<'test> {
 
                 self.compose_and_run(
                     test_client,
-                    self.config.run_lib_path.to_str().unwrap(),
-                    Some(aux_dir.to_str().unwrap()),
+                    self.config.run_lib_path.as_path(),
+                    Some(aux_dir.as_path()),
                     None,
                 )
             }
@@ -1038,8 +1020,8 @@ impl<'test> TestCx<'test> {
 
                 self.compose_and_run(
                     wr_run,
-                    self.config.run_lib_path.to_str().unwrap(),
-                    Some(aux_dir.to_str().unwrap()),
+                    self.config.run_lib_path.as_path(),
+                    Some(aux_dir.as_path()),
                     None,
                 )
             }
@@ -1053,8 +1035,8 @@ impl<'test> TestCx<'test> {
 
                 self.compose_and_run(
                     program,
-                    self.config.run_lib_path.to_str().unwrap(),
-                    Some(aux_dir.to_str().unwrap()),
+                    self.config.run_lib_path.as_path(),
+                    Some(aux_dir.as_path()),
                     None,
                 )
             }
@@ -1075,7 +1057,7 @@ impl<'test> TestCx<'test> {
         let test_ab =
             of.file.parent().expect("test file path has no parent").join("auxiliary").join(rel_ab);
         if !test_ab.exists() {
-            self.fatal(&format!("aux-build `{}` source not found", test_ab.display()))
+            self.fatal(&format!("aux-build `{}` source not found", test_ab))
         }
 
         TestPaths {
@@ -1112,7 +1094,7 @@ impl<'test> TestCx<'test> {
             || !self.props.aux.proc_macros.is_empty()
     }
 
-    fn aux_output_dir(&self) -> PathBuf {
+    fn aux_output_dir(&self) -> Utf8PathBuf {
         let aux_dir = self.aux_output_dir_name();
 
         if !self.props.aux.builds.is_empty() {
@@ -1128,7 +1110,7 @@ impl<'test> TestCx<'test> {
         aux_dir
     }
 
-    fn build_all_auxiliary(&self, of: &TestPaths, aux_dir: &Path, rustc: &mut Command) {
+    fn build_all_auxiliary(&self, of: &TestPaths, aux_dir: &Utf8Path, rustc: &mut Command) {
         for rel_ab in &self.props.aux.builds {
             self.build_auxiliary(of, rel_ab, &aux_dir, None);
         }
@@ -1148,12 +1130,7 @@ impl<'test> TestCx<'test> {
             |rustc: &mut Command, aux_name: &str, aux_path: &str, aux_type: AuxType| {
                 let lib_name = get_lib_name(&path_to_crate_name(aux_path), aux_type);
                 if let Some(lib_name) = lib_name {
-                    rustc.arg("--extern").arg(format!(
-                        "{}={}/{}",
-                        aux_name,
-                        aux_dir.display(),
-                        lib_name
-                    ));
+                    rustc.arg("--extern").arg(format!("{}={}/{}", aux_name, aux_dir, lib_name));
                 }
             };
 
@@ -1174,7 +1151,7 @@ impl<'test> TestCx<'test> {
             let aux_type = self.build_auxiliary(of, aux_file, aux_dir, None);
             if let Some(lib_name) = get_lib_name(aux_file.trim_end_matches(".rs"), aux_type) {
                 let lib_path = aux_dir.join(&lib_name);
-                rustc.arg(format!("-Zcodegen-backend={}", lib_path.display()));
+                rustc.arg(format!("-Zcodegen-backend={}", lib_path));
             }
         }
     }
@@ -1190,7 +1167,7 @@ impl<'test> TestCx<'test> {
         if self.props.add_core_stubs {
             let minicore_path = self.build_minicore();
             rustc.arg("--extern");
-            rustc.arg(&format!("minicore={}", minicore_path.to_str().unwrap()));
+            rustc.arg(&format!("minicore={}", minicore_path));
         }
 
         let aux_dir = self.aux_output_dir();
@@ -1200,15 +1177,15 @@ impl<'test> TestCx<'test> {
         self.props.unset_rustc_env.iter().fold(&mut rustc, Command::env_remove);
         self.compose_and_run(
             rustc,
-            self.config.compile_lib_path.to_str().unwrap(),
-            Some(aux_dir.to_str().unwrap()),
+            self.config.compile_lib_path.as_path(),
+            Some(aux_dir.as_path()),
             input,
         )
     }
 
     /// Builds `minicore`. Returns the path to the minicore rlib within the base test output
     /// directory.
-    fn build_minicore(&self) -> PathBuf {
+    fn build_minicore(&self) -> Utf8PathBuf {
         let output_file_path = self.output_base_dir().join("libminicore.rlib");
         let mut rustc = self.make_compile_args(
             &self.config.minicore_path,
@@ -1222,14 +1199,10 @@ impl<'test> TestCx<'test> {
         rustc.args(&["--crate-type", "rlib"]);
         rustc.arg("-Cpanic=abort");
 
-        let res =
-            self.compose_and_run(rustc, self.config.compile_lib_path.to_str().unwrap(), None, None);
+        let res = self.compose_and_run(rustc, self.config.compile_lib_path.as_path(), None, None);
         if !res.status.success() {
             self.fatal_proc_rec(
-                &format!(
-                    "auxiliary build of {:?} failed to compile: ",
-                    self.config.minicore_path.display()
-                ),
+                &format!("auxiliary build of {} failed to compile: ", self.config.minicore_path),
                 &res,
             );
         }
@@ -1244,7 +1217,7 @@ impl<'test> TestCx<'test> {
         &self,
         of: &TestPaths,
         source_path: &str,
-        aux_dir: &Path,
+        aux_dir: &Utf8Path,
         aux_type: Option<AuxType>,
     ) -> AuxType {
         let aux_testpaths = self.compute_aux_test_paths(of, source_path);
@@ -1335,16 +1308,13 @@ impl<'test> TestCx<'test> {
 
         let auxres = aux_cx.compose_and_run(
             aux_rustc,
-            aux_cx.config.compile_lib_path.to_str().unwrap(),
-            Some(aux_dir.to_str().unwrap()),
+            aux_cx.config.compile_lib_path.as_path(),
+            Some(aux_dir.as_path()),
             None,
         );
         if !auxres.status.success() {
             self.fatal_proc_rec(
-                &format!(
-                    "auxiliary build of {:?} failed to compile: ",
-                    aux_testpaths.file.display()
-                ),
+                &format!("auxiliary build of {} failed to compile: ", aux_testpaths.file),
                 &auxres,
             );
         }
@@ -1353,8 +1323,8 @@ impl<'test> TestCx<'test> {
 
     fn read2_abbreviated(&self, child: Child) -> (Output, Truncated) {
         let mut filter_paths_from_len = Vec::new();
-        let mut add_path = |path: &Path| {
-            let path = path.display().to_string();
+        let mut add_path = |path: &Utf8Path| {
+            let path = path.to_string();
             let windows = path.replace("\\", "\\\\");
             if windows != path {
                 filter_paths_from_len.push(windows);
@@ -1376,8 +1346,8 @@ impl<'test> TestCx<'test> {
     fn compose_and_run(
         &self,
         mut command: Command,
-        lib_path: &str,
-        aux_path: Option<&str>,
+        lib_path: &Utf8Path,
+        aux_path: Option<&Utf8Path>,
         input: Option<String>,
     ) -> ProcRes {
         let cmdline = {
@@ -1422,9 +1392,9 @@ impl<'test> TestCx<'test> {
         matches!(self.config.suite.as_str(), "rustdoc-ui" | "rustdoc-js" | "rustdoc-json")
     }
 
-    fn get_mir_dump_dir(&self) -> PathBuf {
+    fn get_mir_dump_dir(&self) -> Utf8PathBuf {
         let mut mir_dump_dir = self.config.build_test_suite_root.clone();
-        debug!("input_file: {:?}", self.testpaths.file);
+        debug!("input_file: {}", self.testpaths.file);
         mir_dump_dir.push(&self.testpaths.relative_dir);
         mir_dump_dir.push(self.testpaths.file.file_stem().unwrap());
         mir_dump_dir
@@ -1432,7 +1402,7 @@ impl<'test> TestCx<'test> {
 
     fn make_compile_args(
         &self,
-        input_file: &Path,
+        input_file: &Utf8Path,
         output_file: TargetLocation,
         emit: Emit,
         allow_unused: AllowUnused,
@@ -1473,7 +1443,7 @@ impl<'test> TestCx<'test> {
         // Similarly, vendored sources shouldn't be shown when running from a dist tarball.
         rustc.arg("-Z").arg(format!(
             "ignore-directory-in-diagnostics-source-blocks={}",
-            self.config.src_root.join("vendor").to_str().unwrap(),
+            self.config.src_root.join("vendor"),
         ));
 
         // Optionally prevent default --sysroot if specified in test compile-flags.
@@ -1497,7 +1467,7 @@ impl<'test> TestCx<'test> {
 
         if !is_rustdoc {
             if let Some(ref incremental_dir) = self.props.incremental_dir {
-                rustc.args(&["-C", &format!("incremental={}", incremental_dir.display())]);
+                rustc.args(&["-C", &format!("incremental={}", incremental_dir)]);
                 rustc.args(&["-Z", "incremental-verify-ich"]);
             }
 
@@ -1541,7 +1511,7 @@ impl<'test> TestCx<'test> {
             let mir_dump_dir = self.get_mir_dump_dir();
             remove_and_create_dir_all(&mir_dump_dir);
             let mut dir_opt = "-Zdump-mir-dir=".to_string();
-            dir_opt.push_str(mir_dump_dir.to_str().unwrap());
+            dir_opt.push_str(mir_dump_dir.as_str());
             debug!("dir_opt: {:?}", dir_opt);
             rustc.arg(dir_opt);
         };
@@ -1634,8 +1604,7 @@ impl<'test> TestCx<'test> {
         if self.props.remap_src_base {
             rustc.arg(format!(
                 "--remap-path-prefix={}={}",
-                self.config.src_test_suite_root.to_str().unwrap(),
-                FAKE_SRC_BASE,
+                self.config.src_test_suite_root, FAKE_SRC_BASE,
             ));
         }
 
@@ -1758,7 +1727,7 @@ impl<'test> TestCx<'test> {
         rustc
     }
 
-    fn make_exe_name(&self) -> PathBuf {
+    fn make_exe_name(&self) -> Utf8PathBuf {
         // Using a single letter here to keep the path length down for
         // Windows.  Some test names get very long.  rustc creates `rcgu`
         // files with the module name appended to it which can more than
@@ -1809,7 +1778,7 @@ impl<'test> TestCx<'test> {
         }
     }
 
-    fn make_cmdline(&self, command: &Command, libpath: &str) -> String {
+    fn make_cmdline(&self, command: &Command, libpath: &Utf8Path) -> String {
         use crate::util;
 
         // Linux and mac don't require adjusting the library search path
@@ -1822,7 +1791,7 @@ impl<'test> TestCx<'test> {
                 format!("{}=\"{}\"", util::lib_path_env_var(), util::make_new_path(path))
             }
 
-            format!("{} {:?}", lib_path_cmd_prefix(libpath), command)
+            format!("{} {:?}", lib_path_cmd_prefix(libpath.as_str()), command)
         }
     }
 
@@ -1836,20 +1805,19 @@ impl<'test> TestCx<'test> {
             return;
         }
 
-        let path = Path::new(proc_name);
+        let path = Utf8Path::new(proc_name);
         let proc_name = if path.file_stem().is_some_and(|p| p == "rmake") {
-            OsString::from_iter(
+            String::from_iter(
                 path.parent()
                     .unwrap()
                     .file_name()
                     .into_iter()
-                    .chain(Some(OsStr::new("/")))
+                    .chain(Some("/"))
                     .chain(path.file_name()),
             )
         } else {
             path.file_name().unwrap().into()
         };
-        let proc_name = proc_name.to_string_lossy();
         println!("------{proc_name} stdout------------------------------");
         println!("{}", out);
         println!("------{proc_name} stderr------------------------------");
@@ -1859,18 +1827,18 @@ impl<'test> TestCx<'test> {
 
     fn dump_output_file(&self, out: &str, extension: &str) {
         let outfile = self.make_out_name(extension);
-        fs::write(&outfile, out).unwrap();
+        fs::write(outfile.as_std_path(), out).unwrap();
     }
 
     /// Creates a filename for output with the given extension.
     /// E.g., `/.../testname.revision.mode/testname.extension`.
-    fn make_out_name(&self, extension: &str) -> PathBuf {
+    fn make_out_name(&self, extension: &str) -> Utf8PathBuf {
         self.output_base_name().with_extension(extension)
     }
 
     /// Gets the directory where auxiliary files are written.
     /// E.g., `/.../testname.revision.mode/auxiliary/`.
-    fn aux_output_dir_name(&self) -> PathBuf {
+    fn aux_output_dir_name(&self) -> Utf8PathBuf {
         self.output_base_dir()
             .join("auxiliary")
             .with_extra_extension(self.config.mode.aux_dir_disambiguator())
@@ -1878,12 +1846,12 @@ impl<'test> TestCx<'test> {
 
     /// Gets the directory where auxiliary binaries are written.
     /// E.g., `/.../testname.revision.mode/auxiliary/bin`.
-    fn aux_bin_output_dir_name(&self) -> PathBuf {
+    fn aux_bin_output_dir_name(&self) -> Utf8PathBuf {
         self.aux_output_dir_name().join("bin")
     }
 
     /// Generates a unique name for the test, such as `testname.revision.mode`.
-    fn output_testname_unique(&self) -> PathBuf {
+    fn output_testname_unique(&self) -> Utf8PathBuf {
         output_testname_unique(self.config, self.testpaths, self.safe_revision())
     }
 
@@ -1896,14 +1864,14 @@ impl<'test> TestCx<'test> {
     /// Gets the absolute path to the directory where all output for the given
     /// test/revision should reside.
     /// E.g., `/path/to/build/host-tuple/test/ui/relative/testname.revision.mode/`.
-    fn output_base_dir(&self) -> PathBuf {
+    fn output_base_dir(&self) -> Utf8PathBuf {
         output_base_dir(self.config, self.testpaths, self.safe_revision())
     }
 
     /// Gets the absolute path to the base filename used as output for the given
     /// test/revision.
     /// E.g., `/.../relative/testname.revision.mode/testname`.
-    fn output_base_name(&self) -> PathBuf {
+    fn output_base_name(&self) -> Utf8PathBuf {
         output_base_name(self.config, self.testpaths, self.safe_revision())
     }
 
@@ -1938,7 +1906,7 @@ impl<'test> TestCx<'test> {
 
     // codegen tests (using FileCheck)
 
-    fn compile_test_and_save_ir(&self) -> (ProcRes, PathBuf) {
+    fn compile_test_and_save_ir(&self) -> (ProcRes, Utf8PathBuf) {
         let output_path = self.output_base_name().with_extension("ll");
         let input_file = &self.testpaths.file;
         let rustc = self.make_compile_args(
@@ -1954,7 +1922,7 @@ impl<'test> TestCx<'test> {
         (proc_res, output_path)
     }
 
-    fn verify_with_filecheck(&self, output: &Path) -> ProcRes {
+    fn verify_with_filecheck(&self, output: &Utf8Path) -> ProcRes {
         let mut filecheck = Command::new(self.config.llvm_filecheck.as_ref().unwrap());
         filecheck.arg("--input-file").arg(output).arg(&self.testpaths.file);
 
@@ -1983,7 +1951,8 @@ impl<'test> TestCx<'test> {
         // Add custom flags supplied by the `filecheck-flags:` test header.
         filecheck.args(&self.props.filecheck_flags);
 
-        self.compose_and_run(filecheck, "", None, None)
+        // FIXME(jieyouxu): don't pass an empty Path
+        self.compose_and_run(filecheck, Utf8Path::new(""), None, None)
     }
 
     fn charset() -> &'static str {
@@ -1991,7 +1960,7 @@ impl<'test> TestCx<'test> {
         if cfg!(target_os = "freebsd") { "ISO-8859-1" } else { "UTF-8" }
     }
 
-    fn compare_to_default_rustdoc(&mut self, out_dir: &Path) {
+    fn compare_to_default_rustdoc(&mut self, out_dir: &Utf8Path) {
         if !self.config.has_html_tidy {
             return;
         }
@@ -2143,12 +2112,8 @@ impl<'test> TestCx<'test> {
         };
     }
 
-    fn get_lines<P: AsRef<Path>>(
-        &self,
-        path: &P,
-        mut other_files: Option<&mut Vec<String>>,
-    ) -> Vec<usize> {
-        let content = fs::read_to_string(&path).unwrap();
+    fn get_lines(&self, path: &Utf8Path, mut other_files: Option<&mut Vec<String>>) -> Vec<usize> {
+        let content = fs::read_to_string(path.as_std_path()).unwrap();
         let mut ignore = false;
         content
             .lines()
@@ -2194,8 +2159,8 @@ impl<'test> TestCx<'test> {
         for other_file in other_files {
             let mut path = self.testpaths.file.clone();
             path.set_file_name(&format!("{}.rs", other_file));
-            let path = fs::canonicalize(path).expect("failed to canonicalize");
-            let normalized = path.to_str().unwrap().replace('\\', "/");
+            let path = path.canonicalize_utf8().expect("failed to canonicalize");
+            let normalized = path.as_str().replace('\\', "/");
             files.insert(normalized, self.get_lines(&path, None));
         }
 
@@ -2379,26 +2344,24 @@ impl<'test> TestCx<'test> {
 
         let mut normalized = output.to_string();
 
-        let mut normalize_path = |from: &Path, to: &str| {
-            let mut from = from.display().to_string();
-            if json {
-                from = from.replace("\\", "\\\\");
-            }
-            normalized = normalized.replace(&from, to);
+        let mut normalize_path = |from: &Utf8Path, to: &str| {
+            let from = if json { &from.as_str().replace("\\", "\\\\") } else { from.as_str() };
+
+            normalized = normalized.replace(from, to);
         };
 
         let parent_dir = self.testpaths.file.parent().unwrap();
         normalize_path(parent_dir, "$DIR");
 
         if self.props.remap_src_base {
-            let mut remapped_parent_dir = PathBuf::from(FAKE_SRC_BASE);
-            if self.testpaths.relative_dir != Path::new("") {
+            let mut remapped_parent_dir = Utf8PathBuf::from(FAKE_SRC_BASE);
+            if self.testpaths.relative_dir != Utf8Path::new("") {
                 remapped_parent_dir.push(&self.testpaths.relative_dir);
             }
             normalize_path(&remapped_parent_dir, "$DIR");
         }
 
-        let base_dir = Path::new("/rustc/FAKE_PREFIX");
+        let base_dir = Utf8Path::new("/rustc/FAKE_PREFIX");
         // Fake paths into the libstd/libcore
         normalize_path(&base_dir.join("library"), "$SRC_DIR");
         // `ui-fulldeps` tests can show paths to the compiler source when testing macros from
@@ -2408,19 +2371,26 @@ impl<'test> TestCx<'test> {
 
         // Real paths into the libstd/libcore
         let rust_src_dir = &self.config.sysroot_base.join("lib/rustlib/src/rust");
-        rust_src_dir.try_exists().expect(&*format!("{} should exists", rust_src_dir.display()));
-        let rust_src_dir = rust_src_dir.read_link().unwrap_or(rust_src_dir.to_path_buf());
+        rust_src_dir.try_exists().expect(&*format!("{} should exists", rust_src_dir));
+        let rust_src_dir = rust_src_dir.read_link_utf8().unwrap_or(rust_src_dir.to_path_buf());
         normalize_path(&rust_src_dir.join("library"), "$SRC_DIR_REAL");
 
         // eg.
         // /home/user/rust/build/x86_64-unknown-linux-gnu/test/ui/<test_dir>/$name.$revision.$mode/
         normalize_path(&self.output_base_dir(), "$TEST_BUILD_DIR");
+        // Same as above, but with a canonicalized path.
+        // This is required because some tests print canonical paths inside test build directory,
+        // so if the build directory is a symlink, normalization doesn't help.
+        //
+        // NOTE: There are also tests which print the non-canonical name, so we need both this and
+        // the above normalizations.
+        normalize_path(&self.output_base_dir().canonicalize_utf8().unwrap(), "$TEST_BUILD_DIR");
         // eg. /home/user/rust/build
         normalize_path(&self.config.build_root, "$BUILD_DIR");
 
         if json {
             // escaped newlines in json strings should be readable
-            // in the stderr files. There's no point int being correct,
+            // in the stderr files. There's no point in being correct,
             // since only humans process the stderr files.
             // Thus we just turn escaped newlines back into newlines.
             normalized = normalized.replace("\\n", "\n");
@@ -2549,7 +2519,7 @@ impl<'test> TestCx<'test> {
             .replace("\r\n", "\n")
     }
 
-    fn expected_output_path(&self, kind: &str) -> PathBuf {
+    fn expected_output_path(&self, kind: &str) -> Utf8PathBuf {
         let mut path =
             expected_output_path(&self.testpaths, self.revision, &self.config.compare_mode, kind);
 
@@ -2578,19 +2548,18 @@ impl<'test> TestCx<'test> {
         }
     }
 
-    fn load_expected_output_from_path(&self, path: &Path) -> Result<String, String> {
-        fs::read_to_string(path).map_err(|err| {
-            format!("failed to load expected output from `{}`: {}", path.display(), err)
-        })
+    fn load_expected_output_from_path(&self, path: &Utf8Path) -> Result<String, String> {
+        fs::read_to_string(path)
+            .map_err(|err| format!("failed to load expected output from `{}`: {}", path, err))
     }
 
-    fn delete_file(&self, file: &Path) {
+    fn delete_file(&self, file: &Utf8Path) {
         if !file.exists() {
             // Deleting a nonexistent file would error.
             return;
         }
-        if let Err(e) = fs::remove_file(file) {
-            self.fatal(&format!("failed to delete `{}`: {}", file.display(), e,));
+        if let Err(e) = fs::remove_file(file.as_std_path()) {
+            self.fatal(&format!("failed to delete `{}`: {}", file, e,));
         }
     }
 
@@ -2696,8 +2665,8 @@ impl<'test> TestCx<'test> {
     fn show_diff(
         &self,
         stream: &str,
-        expected_path: &Path,
-        actual_path: &Path,
+        expected_path: &Utf8Path,
+        actual_path: &Utf8Path,
         expected: &str,
         actual: &str,
         actual_unnormalized: &str,
@@ -2836,7 +2805,7 @@ impl<'test> TestCx<'test> {
         fs::create_dir_all(&incremental_dir).unwrap();
 
         if self.config.verbose {
-            println!("init_incremental_test: incremental_dir={}", incremental_dir.display());
+            println!("init_incremental_test: incremental_dir={incremental_dir}");
         }
     }
 }
@@ -2894,8 +2863,8 @@ impl ProcRes {
 
 #[derive(Debug)]
 enum TargetLocation {
-    ThisFile(PathBuf),
-    ThisDirectory(PathBuf),
+    ThisFile(Utf8PathBuf),
+    ThisDirectory(Utf8PathBuf),
 }
 
 enum AllowUnused {
diff --git a/src/tools/compiletest/src/runtest/assembly.rs b/src/tools/compiletest/src/runtest/assembly.rs
index 89d7de58c20..91d4f620f71 100644
--- a/src/tools/compiletest/src/runtest/assembly.rs
+++ b/src/tools/compiletest/src/runtest/assembly.rs
@@ -1,4 +1,4 @@
-use std::path::PathBuf;
+use camino::Utf8PathBuf;
 
 use super::{AllowUnused, Emit, LinkToAux, ProcRes, TargetLocation, TestCx};
 
@@ -19,7 +19,7 @@ impl TestCx<'_> {
         }
     }
 
-    fn compile_test_and_save_assembly(&self) -> (ProcRes, PathBuf) {
+    fn compile_test_and_save_assembly(&self) -> (ProcRes, Utf8PathBuf) {
         // This works with both `--emit asm` (as default output name for the assembly)
         // and `ptx-linker` because the latter can write output at requested location.
         let output_path = self.output_base_name().with_extension("s");
diff --git a/src/tools/compiletest/src/runtest/codegen_units.rs b/src/tools/compiletest/src/runtest/codegen_units.rs
index 6c866cbef21..8dfa8d18d1a 100644
--- a/src/tools/compiletest/src/runtest/codegen_units.rs
+++ b/src/tools/compiletest/src/runtest/codegen_units.rs
@@ -26,9 +26,7 @@ impl TestCx<'_> {
             .stdout
             .lines()
             .filter(|line| line.starts_with(PREFIX))
-            .map(|line| {
-                line.replace(&self.testpaths.file.display().to_string(), "TEST_PATH").to_string()
-            })
+            .map(|line| line.replace(&self.testpaths.file.as_str(), "TEST_PATH").to_string())
             .map(|line| str_to_mono_item(&line, true))
             .collect();
 
diff --git a/src/tools/compiletest/src/runtest/coverage.rs b/src/tools/compiletest/src/runtest/coverage.rs
index 56fc5baf5f2..41cfeaee35f 100644
--- a/src/tools/compiletest/src/runtest/coverage.rs
+++ b/src/tools/compiletest/src/runtest/coverage.rs
@@ -1,9 +1,9 @@
 //! Code specific to the coverage test suites.
 
 use std::ffi::OsStr;
-use std::path::{Path, PathBuf};
 use std::process::Command;
 
+use camino::{Utf8Path, Utf8PathBuf};
 use glob::glob;
 
 use crate::common::{UI_COVERAGE, UI_COVERAGE_MAP};
@@ -11,7 +11,7 @@ use crate::runtest::{Emit, ProcRes, TestCx, WillExecute};
 use crate::util::static_regex;
 
 impl<'test> TestCx<'test> {
-    fn coverage_dump_path(&self) -> &Path {
+    fn coverage_dump_path(&self) -> &Utf8Path {
         self.config
             .coverage_dump_path
             .as_deref()
@@ -79,10 +79,8 @@ impl<'test> TestCx<'test> {
             std::fs::remove_file(&profdata_path).unwrap();
         }
 
-        let proc_res = self.exec_compiled_test_general(
-            &[("LLVM_PROFILE_FILE", &profraw_path.to_str().unwrap())],
-            false,
-        );
+        let proc_res =
+            self.exec_compiled_test_general(&[("LLVM_PROFILE_FILE", profraw_path.as_str())], false);
         if self.props.failure_status.is_some() {
             self.check_correct_failure_status(&proc_res);
         } else if !proc_res.status.success() {
@@ -158,8 +156,8 @@ impl<'test> TestCx<'test> {
     /// `.profraw` files and doctest executables to the given vectors.
     fn run_doctests_for_coverage(
         &self,
-        profraw_paths: &mut Vec<PathBuf>,
-        bin_paths: &mut Vec<PathBuf>,
+        profraw_paths: &mut Vec<Utf8PathBuf>,
+        bin_paths: &mut Vec<Utf8PathBuf>,
     ) {
         // Put .profraw files and doctest executables in dedicated directories,
         // to make it easier to glob them all later.
@@ -204,10 +202,9 @@ impl<'test> TestCx<'test> {
             self.fatal_proc_rec("rustdoc --test failed!", &proc_res)
         }
 
-        fn glob_iter(path: impl AsRef<Path>) -> impl Iterator<Item = PathBuf> {
-            let path_str = path.as_ref().to_str().unwrap();
-            let iter = glob(path_str).unwrap();
-            iter.map(Result::unwrap)
+        fn glob_iter(path: impl AsRef<Utf8Path>) -> impl Iterator<Item = Utf8PathBuf> {
+            let iter = glob(path.as_ref().as_str()).unwrap();
+            iter.map(Result::unwrap).map(Utf8PathBuf::try_from).map(Result::unwrap)
         }
 
         // Find all profraw files in the profraw directory.
diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs
index d9e5c3fa0d8..a4103c5b4a9 100644
--- a/src/tools/compiletest/src/runtest/debugger.rs
+++ b/src/tools/compiletest/src/runtest/debugger.rs
@@ -1,7 +1,8 @@
 use std::fmt::Write;
 use std::fs::File;
 use std::io::{BufRead, BufReader};
-use std::path::{Path, PathBuf};
+
+use camino::{Utf8Path, Utf8PathBuf};
 
 use crate::common::Config;
 use crate::runtest::ProcRes;
@@ -15,11 +16,15 @@ pub(super) struct DebuggerCommands {
     /// Contains the source line number to check and the line itself
     check_lines: Vec<(usize, String)>,
     /// Source file name
-    file: PathBuf,
+    file: Utf8PathBuf,
 }
 
 impl DebuggerCommands {
-    pub fn parse_from(file: &Path, config: &Config, debugger_prefix: &str) -> Result<Self, String> {
+    pub fn parse_from(
+        file: &Utf8Path,
+        config: &Config,
+        debugger_prefix: &str,
+    ) -> Result<Self, String> {
         let command_directive = format!("{debugger_prefix}-command");
         let check_directive = format!("{debugger_prefix}-check");
 
@@ -27,7 +32,7 @@ impl DebuggerCommands {
         let mut commands = vec![];
         let mut check_lines = vec![];
         let mut counter = 0;
-        let reader = BufReader::new(File::open(file).unwrap());
+        let reader = BufReader::new(File::open(file.as_std_path()).unwrap());
         for (line_no, line) in reader.lines().enumerate() {
             counter += 1;
             let line = line.map_err(|e| format!("Error while parsing debugger commands: {}", e))?;
@@ -50,7 +55,7 @@ impl DebuggerCommands {
             }
         }
 
-        Ok(Self { commands, breakpoint_lines, check_lines, file: file.to_owned() })
+        Ok(Self { commands, breakpoint_lines, check_lines, file: file.to_path_buf() })
     }
 
     /// Given debugger output and lines to check, ensure that every line is
@@ -81,10 +86,10 @@ impl DebuggerCommands {
         if missing.is_empty() {
             Ok(())
         } else {
-            let fname = self.file.file_name().unwrap().to_string_lossy();
+            let fname = self.file.file_name().unwrap();
             let mut msg = format!(
                 "check directive(s) from `{}` not found in debugger output. errors:",
-                self.file.display()
+                self.file
             );
 
             for (src_lineno, err_line) in missing {
diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs
index 170b8a80996..31240dff9a1 100644
--- a/src/tools/compiletest/src/runtest/debuginfo.rs
+++ b/src/tools/compiletest/src/runtest/debuginfo.rs
@@ -1,9 +1,9 @@
 use std::ffi::{OsStr, OsString};
 use std::fs::File;
 use std::io::{BufRead, BufReader, Read};
-use std::path::Path;
 use std::process::{Command, Output, Stdio};
 
+use camino::Utf8Path;
 use tracing::debug;
 
 use super::debugger::DebuggerCommands;
@@ -73,11 +73,11 @@ impl TestCx<'_> {
         let mut js_extension = self.testpaths.file.clone();
         js_extension.set_extension("cdb.js");
         if js_extension.exists() {
-            script_str.push_str(&format!(".scriptload \"{}\"\n", js_extension.to_string_lossy()));
+            script_str.push_str(&format!(".scriptload \"{}\"\n", js_extension));
         }
 
         // Set breakpoints on every line that contains the string "#break"
-        let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy();
+        let source_file_name = self.testpaths.file.file_name().unwrap();
         for line in &dbg_cmds.breakpoint_lines {
             script_str.push_str(&format!("bp `{}:{}`\n", source_file_name, line));
         }
@@ -104,7 +104,7 @@ impl TestCx<'_> {
 
         let debugger_run_result = self.compose_and_run(
             cdb,
-            self.config.run_lib_path.to_str().unwrap(),
+            self.config.run_lib_path.as_path(),
             None, // aux_path
             None, // input
         );
@@ -151,16 +151,11 @@ impl TestCx<'_> {
         if is_android_gdb_target(&self.config.target) {
             cmds = cmds.replace("run", "continue");
 
-            let tool_path = match self.config.android_cross_path.to_str() {
-                Some(x) => x.to_owned(),
-                None => self.fatal("cannot find android cross path"),
-            };
-
             // write debugger script
             let mut script_str = String::with_capacity(2048);
             script_str.push_str(&format!("set charset {}\n", Self::charset()));
-            script_str.push_str(&format!("set sysroot {}\n", tool_path));
-            script_str.push_str(&format!("file {}\n", exe_file.to_str().unwrap()));
+            script_str.push_str(&format!("set sysroot {}\n", &self.config.android_cross_path));
+            script_str.push_str(&format!("file {}\n", exe_file));
             script_str.push_str("target remote :5039\n");
             script_str.push_str(&format!(
                 "set solib-search-path \
@@ -169,12 +164,8 @@ impl TestCx<'_> {
             ));
             for line in &dbg_cmds.breakpoint_lines {
                 script_str.push_str(
-                    format!(
-                        "break {:?}:{}\n",
-                        self.testpaths.file.file_name().unwrap().to_string_lossy(),
-                        *line
-                    )
-                    .as_str(),
+                    format!("break {}:{}\n", self.testpaths.file.file_name().unwrap(), *line)
+                        .as_str(),
                 );
             }
             script_str.push_str(&cmds);
@@ -203,7 +194,7 @@ impl TestCx<'_> {
                 self.config.adb_test_dir.clone(),
                 if self.config.target.contains("aarch64") { "64" } else { "" },
                 self.config.adb_test_dir.clone(),
-                exe_file.file_name().unwrap().to_str().unwrap()
+                exe_file.file_name().unwrap()
             );
 
             debug!("adb arg: {}", adb_arg);
@@ -241,7 +232,8 @@ impl TestCx<'_> {
             let cmdline = {
                 let mut gdb = Command::new(&format!("{}-gdb", self.config.target));
                 gdb.args(debugger_opts);
-                let cmdline = self.make_cmdline(&gdb, "");
+                // FIXME(jieyouxu): don't pass an empty Path
+                let cmdline = self.make_cmdline(&gdb, Utf8Path::new(""));
                 logv(self.config, format!("executing {}", cmdline));
                 cmdline
             };
@@ -258,7 +250,6 @@ impl TestCx<'_> {
             }
         } else {
             let rust_pp_module_abs_path = self.config.src_root.join("src").join("etc");
-            let rust_pp_module_abs_path = rust_pp_module_abs_path.to_str().unwrap();
             // write debugger script
             let mut script_str = String::with_capacity(2048);
             script_str.push_str(&format!("set charset {}\n", Self::charset()));
@@ -273,17 +264,15 @@ impl TestCx<'_> {
                         // GDB's script auto loading safe path
                         script_str.push_str(&format!(
                             "add-auto-load-safe-path {}\n",
-                            rust_pp_module_abs_path.replace(r"\", r"\\")
+                            rust_pp_module_abs_path.as_str().replace(r"\", r"\\")
                         ));
 
-                        let output_base_dir = self.output_base_dir().to_str().unwrap().to_owned();
-
                         // Add the directory containing the output binary to
                         // include embedded pretty printers to GDB's script
                         // auto loading safe path
                         script_str.push_str(&format!(
                             "add-auto-load-safe-path {}\n",
-                            output_base_dir.replace(r"\", r"\\")
+                            self.output_base_dir().as_str().replace(r"\", r"\\")
                         ));
                     }
                 }
@@ -300,12 +289,13 @@ impl TestCx<'_> {
             script_str.push_str("set print pretty off\n");
 
             // Add the pretty printer directory to GDB's source-file search path
-            script_str
-                .push_str(&format!("directory {}\n", rust_pp_module_abs_path.replace(r"\", r"\\")));
+            script_str.push_str(&format!(
+                "directory {}\n",
+                rust_pp_module_abs_path.as_str().replace(r"\", r"\\")
+            ));
 
             // Load the target executable
-            script_str
-                .push_str(&format!("file {}\n", exe_file.to_str().unwrap().replace(r"\", r"\\")));
+            script_str.push_str(&format!("file {}\n", exe_file.as_str().replace(r"\", r"\\")));
 
             // Force GDB to print values in the Rust format.
             script_str.push_str("set language rust\n");
@@ -314,7 +304,7 @@ impl TestCx<'_> {
             for line in &dbg_cmds.breakpoint_lines {
                 script_str.push_str(&format!(
                     "break '{}':{}\n",
-                    self.testpaths.file.file_name().unwrap().to_string_lossy(),
+                    self.testpaths.file.file_name().unwrap(),
                     *line
                 ));
             }
@@ -340,7 +330,7 @@ impl TestCx<'_> {
             gdb.args(debugger_opts).env("PYTHONPATH", pythonpath);
 
             debugger_run_result =
-                self.compose_and_run(gdb, self.config.run_lib_path.to_str().unwrap(), None, None);
+                self.compose_and_run(gdb, self.config.run_lib_path.as_path(), None, None);
         }
 
         if !debugger_run_result.status.success() {
@@ -409,14 +399,14 @@ impl TestCx<'_> {
 
         script_str.push_str(&format!(
             "command script import {}/lldb_lookup.py\n",
-            rust_pp_module_abs_path.to_str().unwrap()
+            rust_pp_module_abs_path
         ));
         File::open(rust_pp_module_abs_path.join("lldb_commands"))
             .and_then(|mut file| file.read_to_string(&mut script_str))
             .expect("Failed to read lldb_commands");
 
         // Set breakpoints on every line that contains the string "#break"
-        let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy();
+        let source_file_name = self.testpaths.file.file_name().unwrap();
         for line in &dbg_cmds.breakpoint_lines {
             script_str.push_str(&format!(
                 "breakpoint set --file '{}' --line {}\n",
@@ -450,7 +440,7 @@ impl TestCx<'_> {
         }
     }
 
-    fn run_lldb(&self, test_executable: &Path, debugger_script: &Path) -> ProcRes {
+    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");
         let pythonpath = if let Ok(pp) = std::env::var("PYTHONPATH") {
diff --git a/src/tools/compiletest/src/runtest/js_doc.rs b/src/tools/compiletest/src/runtest/js_doc.rs
index d630affbec1..fd53f01ca17 100644
--- a/src/tools/compiletest/src/runtest/js_doc.rs
+++ b/src/tools/compiletest/src/runtest/js_doc.rs
@@ -9,8 +9,7 @@ impl TestCx<'_> {
 
             self.document(&out_dir, &self.testpaths);
 
-            let file_stem =
-                self.testpaths.file.file_stem().and_then(|f| f.to_str()).expect("no file stem");
+            let file_stem = self.testpaths.file.file_stem().expect("no file stem");
             let res = self.run_command_to_procres(
                 Command::new(&nodejs)
                     .arg(self.config.src_root.join("src/tools/rustdoc-js/tester.js"))
diff --git a/src/tools/compiletest/src/runtest/mir_opt.rs b/src/tools/compiletest/src/runtest/mir_opt.rs
index d1ec0035744..ded6a68fe58 100644
--- a/src/tools/compiletest/src/runtest/mir_opt.rs
+++ b/src/tools/compiletest/src/runtest/mir_opt.rs
@@ -1,6 +1,6 @@
 use std::fs;
-use std::path::{Path, PathBuf};
 
+use camino::{Utf8Path, Utf8PathBuf};
 use glob::glob;
 use miropt_test_tools::{MiroptTest, MiroptTestFile, files_for_miropt_test};
 use tracing::debug;
@@ -14,7 +14,7 @@ impl TestCx<'_> {
         let should_run = self.should_run(pm);
 
         let mut test_info = files_for_miropt_test(
-            &self.testpaths.file,
+            &self.testpaths.file.as_std_path(),
             self.config.get_pointer_width(),
             self.config.target_cfg().panic.for_miropt_test_tools(),
         );
@@ -38,20 +38,15 @@ impl TestCx<'_> {
 
     fn check_mir_dump(&self, test_info: MiroptTest) {
         let test_dir = self.testpaths.file.parent().unwrap();
-        let test_crate =
-            self.testpaths.file.file_stem().unwrap().to_str().unwrap().replace('-', "_");
+        let test_crate = self.testpaths.file.file_stem().unwrap().replace('-', "_");
 
         let MiroptTest { run_filecheck, suffix, files, passes: _ } = test_info;
 
         if self.config.bless {
-            for e in
-                glob(&format!("{}/{}.*{}.mir", test_dir.display(), test_crate, suffix)).unwrap()
-            {
+            for e in glob(&format!("{}/{}.*{}.mir", test_dir, test_crate, suffix)).unwrap() {
                 fs::remove_file(e.unwrap()).unwrap();
             }
-            for e in
-                glob(&format!("{}/{}.*{}.diff", test_dir.display(), test_crate, suffix)).unwrap()
-            {
+            for e in glob(&format!("{}/{}.*{}.diff", test_dir, test_crate, suffix)).unwrap() {
                 fs::remove_file(e.unwrap()).unwrap();
             }
         }
@@ -60,19 +55,15 @@ impl TestCx<'_> {
             let dumped_string = if let Some(after) = to_file {
                 self.diff_mir_files(from_file.into(), after.into())
             } else {
-                let mut output_file = PathBuf::new();
+                let mut output_file = Utf8PathBuf::new();
                 output_file.push(self.get_mir_dump_dir());
                 output_file.push(&from_file);
-                debug!(
-                    "comparing the contents of: {} with {}",
-                    output_file.display(),
-                    expected_file.display()
-                );
+                debug!("comparing the contents of: {} with {:?}", output_file, expected_file);
                 if !output_file.exists() {
                     panic!(
                         "Output file `{}` from test does not exist, available files are in `{}`",
-                        output_file.display(),
-                        output_file.parent().unwrap().display()
+                        output_file,
+                        output_file.parent().unwrap()
                     );
                 }
                 self.check_mir_test_timestamp(&from_file, &output_file);
@@ -107,21 +98,20 @@ impl TestCx<'_> {
         }
     }
 
-    fn diff_mir_files(&self, before: PathBuf, after: PathBuf) -> String {
-        let to_full_path = |path: PathBuf| {
+    fn diff_mir_files(&self, before: Utf8PathBuf, after: Utf8PathBuf) -> String {
+        let to_full_path = |path: Utf8PathBuf| {
             let full = self.get_mir_dump_dir().join(&path);
             if !full.exists() {
                 panic!(
                     "the mir dump file for {} does not exist (requested in {})",
-                    path.display(),
-                    self.testpaths.file.display(),
+                    path, self.testpaths.file,
                 );
             }
             full
         };
         let before = to_full_path(before);
         let after = to_full_path(after);
-        debug!("comparing the contents of: {} with {}", before.display(), after.display());
+        debug!("comparing the contents of: {} with {}", before, after);
         let before = fs::read_to_string(before).unwrap();
         let after = fs::read_to_string(after).unwrap();
         let before = self.normalize_output(&before, &[]);
@@ -138,8 +128,8 @@ impl TestCx<'_> {
         dumped_string
     }
 
-    fn check_mir_test_timestamp(&self, test_name: &str, output_file: &Path) {
-        let t = |file| fs::metadata(file).unwrap().modified().unwrap();
+    fn check_mir_test_timestamp(&self, test_name: &str, output_file: &Utf8Path) {
+        let t = |file: &Utf8Path| fs::metadata(file.as_std_path()).unwrap().modified().unwrap();
         let source_file = &self.testpaths.file;
         let output_time = t(output_file);
         let source_time = t(source_file);
@@ -147,8 +137,7 @@ impl TestCx<'_> {
             debug!("source file time: {:?} output file time: {:?}", source_time, output_time);
             panic!(
                 "test source file `{}` is newer than potentially stale output file `{}`.",
-                source_file.display(),
-                test_name
+                source_file, test_name
             );
         }
     }
diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs
index 073116933bd..a5ce929f9b8 100644
--- a/src/tools/compiletest/src/runtest/run_make.rs
+++ b/src/tools/compiletest/src/runtest/run_make.rs
@@ -1,8 +1,8 @@
-use std::path::Path;
 use std::process::{Command, Output, Stdio};
 use std::{env, fs};
 
 use build_helper::fs::{ignore_not_found, recursive_remove};
+use camino::{Utf8Path, Utf8PathBuf};
 
 use super::{ProcRes, TestCx, disable_error_reporting};
 use crate::util::{copy_dir_all, dylib_env_var};
@@ -39,14 +39,16 @@ impl TestCx<'_> {
         // Copy all input files (apart from rmake.rs) to the temporary directory,
         // so that the input directory structure from `tests/run-make/<test>` is mirrored
         // to the `rmake_out` directory.
-        for path in walkdir::WalkDir::new(&self.testpaths.file).min_depth(1) {
-            let path = path.unwrap().path().to_path_buf();
+        for entry in walkdir::WalkDir::new(&self.testpaths.file).min_depth(1) {
+            let entry = entry.unwrap();
+            let path = entry.path();
+            let path = <&Utf8Path>::try_from(path).unwrap();
             if path.file_name().is_some_and(|s| s != "rmake.rs") {
                 let target = rmake_out_dir.join(path.strip_prefix(&self.testpaths.file).unwrap());
                 if path.is_dir() {
-                    copy_dir_all(&path, target).unwrap();
+                    copy_dir_all(&path, &target).unwrap();
                 } else {
-                    fs::copy(&path, target).unwrap();
+                    fs::copy(path.as_std_path(), target).unwrap();
                 }
             }
         }
@@ -83,8 +85,10 @@ impl TestCx<'_> {
         //    on some linux distros.
         // 2. Specific library paths in `self.config.compile_lib_path` needed for running rustc.
 
-        let base_dylib_search_paths =
-            Vec::from_iter(env::split_paths(&env::var(dylib_env_var()).unwrap()));
+        let base_dylib_search_paths = Vec::from_iter(
+            env::split_paths(&env::var(dylib_env_var()).unwrap())
+                .map(|p| Utf8PathBuf::try_from(p).expect("dylib env var contains non-UTF8 paths")),
+        );
 
         // Calculate the paths of the recipe binary. As previously discussed, this is placed at
         // `<base_dir>/<bin_name>` with `bin_name` being `rmake` or `rmake.exe` depending on
@@ -113,13 +117,13 @@ impl TestCx<'_> {
             .arg("-o")
             .arg(&recipe_bin)
             // Specify library search paths for `run_make_support`.
-            .arg(format!("-Ldependency={}", &support_lib_path.parent().unwrap().to_string_lossy()))
-            .arg(format!("-Ldependency={}", &support_lib_deps.to_string_lossy()))
-            .arg(format!("-Ldependency={}", &support_lib_deps_deps.to_string_lossy()))
+            .arg(format!("-Ldependency={}", &support_lib_path.parent().unwrap()))
+            .arg(format!("-Ldependency={}", &support_lib_deps))
+            .arg(format!("-Ldependency={}", &support_lib_deps_deps))
             // Provide `run_make_support` as extern prelude, so test writers don't need to write
             // `extern run_make_support;`.
             .arg("--extern")
-            .arg(format!("run_make_support={}", &support_lib_path.to_string_lossy()))
+            .arg(format!("run_make_support={}", &support_lib_path))
             .arg("--edition=2021")
             .arg(&self.testpaths.file.join("rmake.rs"))
             .arg("-Cprefer-dynamic");
@@ -240,7 +244,7 @@ impl TestCx<'_> {
         if self.config.target.contains("msvc") && !self.config.cc.is_empty() {
             // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe`
             // and that `lib.exe` lives next to it.
-            let lib = Path::new(&self.config.cc).parent().unwrap().join("lib.exe");
+            let lib = Utf8Path::new(&self.config.cc).parent().unwrap().join("lib.exe");
 
             // MSYS doesn't like passing flags of the form `/foo` as it thinks it's
             // a path and instead passes `C:\msys64\foo`, so convert all
@@ -262,8 +266,8 @@ impl TestCx<'_> {
 
             cmd.env("IS_MSVC", "1")
                 .env("IS_WINDOWS", "1")
-                .env("MSVC_LIB", format!("'{}' -nologo", lib.display()))
-                .env("MSVC_LIB_PATH", format!("{}", lib.display()))
+                .env("MSVC_LIB", format!("'{}' -nologo", lib))
+                .env("MSVC_LIB_PATH", &lib)
                 // Note: we diverge from legacy run_make and don't lump `CC` the compiler and
                 // default flags together.
                 .env("CC_DEFAULT_FLAGS", &cflags)
diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs
index 974e5170465..e87b037cd28 100644
--- a/src/tools/compiletest/src/runtest/ui.rs
+++ b/src/tools/compiletest/src/runtest/ui.rs
@@ -68,7 +68,7 @@ impl TestCx<'_> {
             {
                 let mut coverage_file_path = self.config.build_test_suite_root.clone();
                 coverage_file_path.push("rustfix_missing_coverage.txt");
-                debug!("coverage_file_path: {}", coverage_file_path.display());
+                debug!("coverage_file_path: {}", coverage_file_path);
 
                 let mut file = OpenOptions::new()
                     .create(true)
@@ -76,8 +76,8 @@ impl TestCx<'_> {
                     .open(coverage_file_path.as_path())
                     .expect("could not create or open file");
 
-                if let Err(e) = writeln!(file, "{}", self.testpaths.file.display()) {
-                    panic!("couldn't write to {}: {e:?}", coverage_file_path.display());
+                if let Err(e) = writeln!(file, "{}", self.testpaths.file) {
+                    panic!("couldn't write to {}: {e:?}", coverage_file_path);
                 }
             }
         } else if self.props.run_rustfix {
@@ -119,7 +119,7 @@ impl TestCx<'_> {
                 self.testpaths.relative_dir.join(self.testpaths.file.file_name().unwrap());
             println!(
                 "To only update this specific test, also pass `--test-args {}`",
-                relative_path_to_file.display(),
+                relative_path_to_file,
             );
             self.fatal_proc_rec(
                 &format!("{} errors occurred comparing output.", errors),
@@ -211,8 +211,6 @@ impl TestCx<'_> {
                 let crate_name =
                     self.testpaths.file.file_stem().expect("test must have a file stem");
                 // crate name must be alphanumeric or `_`.
-                let crate_name =
-                    crate_name.to_str().expect("crate name implies file name must be valid UTF-8");
                 // replace `a.foo` -> `a__foo` for crate name purposes.
                 // replace `revision-name-with-dashes` -> `revision_name_with_underscore`
                 let crate_name = crate_name.replace('.', "__");
diff --git a/src/tools/compiletest/src/tests.rs b/src/tools/compiletest/src/tests.rs
index 43c6dc0a67e..e3e4a81755d 100644
--- a/src/tools/compiletest/src/tests.rs
+++ b/src/tools/compiletest/src/tests.rs
@@ -1,5 +1,3 @@
-use std::ffi::OsString;
-
 use crate::debuggers::{extract_gdb_version, extract_lldb_version};
 use crate::is_test;
 
@@ -60,11 +58,11 @@ fn test_extract_lldb_version() {
 
 #[test]
 fn is_test_test() {
-    assert!(is_test(&OsString::from("a_test.rs")));
-    assert!(!is_test(&OsString::from(".a_test.rs")));
-    assert!(!is_test(&OsString::from("a_cat.gif")));
-    assert!(!is_test(&OsString::from("#a_dog_gif")));
-    assert!(!is_test(&OsString::from("~a_temp_file")));
+    assert!(is_test("a_test.rs"));
+    assert!(!is_test(".a_test.rs"));
+    assert!(!is_test("a_cat.gif"));
+    assert!(!is_test("#a_dog_gif"));
+    assert!(!is_test("~a_temp_file"));
 }
 
 #[test]
diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs
index bff02f1db9f..81f5679aead 100644
--- a/src/tools/compiletest/src/util.rs
+++ b/src/tools/compiletest/src/util.rs
@@ -1,8 +1,7 @@
 use std::env;
-use std::ffi::OsStr;
-use std::path::{Path, PathBuf};
 use std::process::Command;
 
+use camino::{Utf8Path, Utf8PathBuf};
 use tracing::*;
 
 use crate::common::Config;
@@ -34,21 +33,21 @@ pub fn logv(config: &Config, s: String) {
     }
 }
 
-pub trait PathBufExt {
+pub trait Utf8PathBufExt {
     /// Append an extension to the path, even if it already has one.
-    fn with_extra_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf;
+    fn with_extra_extension(&self, extension: &str) -> Utf8PathBuf;
 }
 
-impl PathBufExt for PathBuf {
-    fn with_extra_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
-        if extension.as_ref().is_empty() {
+impl Utf8PathBufExt for Utf8PathBuf {
+    fn with_extra_extension(&self, extension: &str) -> Utf8PathBuf {
+        if extension.is_empty() {
             self.clone()
         } else {
-            let mut fname = self.file_name().unwrap().to_os_string();
-            if !extension.as_ref().to_str().unwrap().starts_with('.') {
-                fname.push(".");
+            let mut fname = self.file_name().unwrap().to_string();
+            if !extension.starts_with('.') {
+                fname.push_str(".");
             }
-            fname.push(extension);
+            fname.push_str(extension);
             self.with_file_name(fname)
         }
     }
@@ -71,22 +70,27 @@ pub fn dylib_env_var() -> &'static str {
 
 /// Adds a list of lookup paths to `cmd`'s dynamic library lookup path.
 /// If the dylib_path_var is already set for this cmd, the old value will be overwritten!
-pub fn add_dylib_path(cmd: &mut Command, paths: impl Iterator<Item = impl Into<PathBuf>>) {
+pub fn add_dylib_path(
+    cmd: &mut Command,
+    paths: impl Iterator<Item = impl Into<std::path::PathBuf>>,
+) {
     let path_env = env::var_os(dylib_env_var());
     let old_paths = path_env.as_ref().map(env::split_paths);
     let new_paths = paths.map(Into::into).chain(old_paths.into_iter().flatten());
     cmd.env(dylib_env_var(), env::join_paths(new_paths).unwrap());
 }
 
-pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> std::io::Result<()> {
-    std::fs::create_dir_all(&dst)?;
-    for entry in std::fs::read_dir(src)? {
+pub fn copy_dir_all(src: &Utf8Path, dst: &Utf8Path) -> std::io::Result<()> {
+    std::fs::create_dir_all(dst.as_std_path())?;
+    for entry in std::fs::read_dir(src.as_std_path())? {
         let entry = entry?;
+        let path = Utf8PathBuf::try_from(entry.path()).unwrap();
+        let file_name = path.file_name().unwrap();
         let ty = entry.file_type()?;
         if ty.is_dir() {
-            copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?;
+            copy_dir_all(&path, &dst.join(file_name))?;
         } else {
-            std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?;
+            std::fs::copy(path.as_std_path(), dst.join(file_name).as_std_path())?;
         }
     }
     Ok(())
diff --git a/src/tools/compiletest/src/util/tests.rs b/src/tools/compiletest/src/util/tests.rs
index b09a183b14e..5bcae0dcee1 100644
--- a/src/tools/compiletest/src/util/tests.rs
+++ b/src/tools/compiletest/src/util/tests.rs
@@ -3,12 +3,12 @@ use super::*;
 #[test]
 fn path_buf_with_extra_extension_test() {
     assert_eq!(
-        PathBuf::from("foo.rs.stderr"),
-        PathBuf::from("foo.rs").with_extra_extension("stderr")
+        Utf8PathBuf::from("foo.rs.stderr"),
+        Utf8PathBuf::from("foo.rs").with_extra_extension("stderr")
     );
     assert_eq!(
-        PathBuf::from("foo.rs.stderr"),
-        PathBuf::from("foo.rs").with_extra_extension(".stderr")
+        Utf8PathBuf::from("foo.rs.stderr"),
+        Utf8PathBuf::from("foo.rs").with_extra_extension(".stderr")
     );
-    assert_eq!(PathBuf::from("foo.rs"), PathBuf::from("foo.rs").with_extra_extension(""));
+    assert_eq!(Utf8PathBuf::from("foo.rs"), Utf8PathBuf::from("foo.rs").with_extra_extension(""));
 }
diff --git a/src/tools/generate-copyright/Cargo.toml b/src/tools/generate-copyright/Cargo.toml
index 404101abd41..ab76d0fc01e 100644
--- a/src/tools/generate-copyright/Cargo.toml
+++ b/src/tools/generate-copyright/Cargo.toml
@@ -8,8 +8,8 @@ description = "Produces a manifest of all the copyrighted materials in the Rust
 
 [dependencies]
 anyhow = "1.0.65"
+askama = "0.13.0"
 cargo_metadata = "0.18.1"
-rinja = "0.3.0"
 serde = { version = "1.0.147", features = ["derive"] }
 serde_json = "1.0.85"
 thiserror = "1"
diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs
index 79e90d88f44..d6ed7261b7c 100644
--- a/src/tools/generate-copyright/src/main.rs
+++ b/src/tools/generate-copyright/src/main.rs
@@ -2,7 +2,7 @@ use std::collections::BTreeMap;
 use std::path::{Path, PathBuf};
 
 use anyhow::Error;
-use rinja::Template;
+use askama::Template;
 
 mod cargo_metadata;
 
@@ -117,7 +117,7 @@ struct Metadata {
 }
 
 /// Describes one node in our metadata tree
-#[derive(serde::Deserialize, rinja::Template, Clone, Debug, PartialEq, Eq)]
+#[derive(serde::Deserialize, Template, Clone, Debug, PartialEq, Eq)]
 #[serde(rename_all = "kebab-case", tag = "type")]
 #[template(path = "Node.html")]
 pub(crate) enum Node {
diff --git a/src/tools/generate-windows-sys/Cargo.toml b/src/tools/generate-windows-sys/Cargo.toml
index f5c0e56bb3c..152cd504abd 100644
--- a/src/tools/generate-windows-sys/Cargo.toml
+++ b/src/tools/generate-windows-sys/Cargo.toml
@@ -4,4 +4,4 @@ version = "0.1.0"
 edition = "2021"
 
 [dependencies.windows-bindgen]
-version = "0.59.0"
+version = "0.61.0"
diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock
index b8100d0e7ad..6f4bd3eab51 100644
--- a/src/tools/miri/Cargo.lock
+++ b/src/tools/miri/Cargo.lock
@@ -39,31 +39,31 @@ dependencies = [
 
 [[package]]
 name = "annotate-snippets"
-version = "0.11.4"
+version = "0.11.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24e35ed54e5ea7997c14ed4c70ba043478db1112e98263b3b035907aa197d991"
+checksum = "710e8eae58854cdc1790fcb56cca04d712a17be849eeb81da2a724bf4bae2bc4"
 dependencies = [
  "anstyle",
- "unicode-width",
+ "unicode-width 0.2.0",
 ]
 
 [[package]]
 name = "anstyle"
-version = "1.0.8"
+version = "1.0.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
+checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
 
 [[package]]
 name = "anyhow"
-version = "1.0.86"
+version = "1.0.97"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
+checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
 
 [[package]]
 name = "autocfg"
-version = "1.3.0"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
 
 [[package]]
 name = "backtrace"
@@ -82,15 +82,15 @@ dependencies = [
 
 [[package]]
 name = "bitflags"
-version = "2.6.0"
+version = "2.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
 
 [[package]]
 name = "bstr"
-version = "1.10.0"
+version = "1.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c"
+checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0"
 dependencies = [
  "memchr",
  "regex-automata",
@@ -98,25 +98,25 @@ dependencies = [
 ]
 
 [[package]]
-name = "byteorder"
-version = "1.5.0"
+name = "bumpalo"
+version = "3.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
 
 [[package]]
 name = "camino"
-version = "1.1.7"
+version = "1.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239"
+checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "cargo-platform"
-version = "0.1.8"
+version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc"
+checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea"
 dependencies = [
  "serde",
 ]
@@ -132,14 +132,14 @@ dependencies = [
  "semver",
  "serde",
  "serde_json",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
 name = "cc"
-version = "1.1.22"
+version = "1.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0"
+checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a"
 dependencies = [
  "shlex",
 ]
@@ -152,18 +152,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chrono"
-version = "0.4.38"
+version = "0.4.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
+checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
 dependencies = [
  "num-traits",
 ]
 
 [[package]]
 name = "chrono-tz"
-version = "0.10.0"
+version = "0.10.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd6dd8046d00723a59a2f8c5f295c515b9bb9a331ee4f8f3d4dd49e428acd3b6"
+checksum = "efdce149c370f133a071ca8ef6ea340b7b88748ab0810097a9e2976eaa34b4f3"
 dependencies = [
  "chrono",
  "chrono-tz-build",
@@ -172,9 +172,9 @@ dependencies = [
 
 [[package]]
 name = "chrono-tz-build"
-version = "0.4.0"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e94fea34d77a245229e7746bd2beb786cd2a896f306ff491fb8cecb3074b10a7"
+checksum = "8f10f8c9340e31fc120ff885fcdb54a0b48e474bbd77cab557f0c30a3e569402"
 dependencies = [
  "parse-zoneinfo",
  "phf_codegen",
@@ -219,12 +219,12 @@ dependencies = [
 
 [[package]]
 name = "colored"
-version = "2.1.0"
+version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
+checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
 dependencies = [
  "lazy_static",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -235,40 +235,40 @@ checksum = "55b672471b4e9f9e95499ea597ff64941a309b2cdbffcc46f2cc5e2d971fd335"
 
 [[package]]
 name = "console"
-version = "0.15.8"
+version = "0.15.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
+checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8"
 dependencies = [
  "encode_unicode",
- "lazy_static",
  "libc",
- "unicode-width",
- "windows-sys 0.52.0",
+ "once_cell",
+ "unicode-width 0.2.0",
+ "windows-sys",
 ]
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.12"
+version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
+checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
 dependencies = [
  "libc",
 ]
 
 [[package]]
 name = "crossbeam-channel"
-version = "0.5.13"
+version = "0.5.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2"
+checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
 dependencies = [
  "crossbeam-utils",
 ]
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.20"
+version = "0.8.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
 
 [[package]]
 name = "crypto-common"
@@ -282,39 +282,39 @@ dependencies = [
 
 [[package]]
 name = "directories"
-version = "5.0.1"
+version = "6.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35"
+checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d"
 dependencies = [
  "dirs-sys",
 ]
 
 [[package]]
 name = "dirs-sys"
-version = "0.4.1"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
+checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
 dependencies = [
  "libc",
  "option-ext",
  "redox_users",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
 name = "encode_unicode"
-version = "0.3.6"
+version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
+checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
 
 [[package]]
 name = "errno"
-version = "0.3.9"
+version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
+checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
 dependencies = [
  "libc",
- "windows-sys 0.52.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -329,9 +329,9 @@ dependencies = [
 
 [[package]]
 name = "fastrand"
-version = "2.1.0"
+version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
 
 [[package]]
 name = "generic-array"
@@ -356,14 +356,14 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.3.1"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
+checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
 dependencies = [
  "cfg-if",
  "libc",
- "wasi 0.13.3+wasi-0.2.2",
- "windows-targets 0.52.6",
+ "r-efi",
+ "wasi 0.14.2+wasi-0.2.4",
 ]
 
 [[package]]
@@ -380,40 +380,41 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
 
 [[package]]
 name = "indicatif"
-version = "0.17.8"
+version = "0.17.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3"
+checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235"
 dependencies = [
  "console",
- "instant",
  "number_prefix",
  "portable-atomic",
- "unicode-width",
+ "unicode-width 0.2.0",
+ "web-time",
 ]
 
 [[package]]
 name = "inout"
-version = "0.1.3"
+version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
+checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
 dependencies = [
  "generic-array",
 ]
 
 [[package]]
-name = "instant"
-version = "0.1.13"
+name = "itoa"
+version = "1.0.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
-dependencies = [
- "cfg-if",
-]
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
 
 [[package]]
-name = "itoa"
-version = "1.0.11"
+name = "js-sys"
+version = "0.3.77"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
+dependencies = [
+ "once_cell",
+ "wasm-bindgen",
+]
 
 [[package]]
 name = "lazy_static"
@@ -429,15 +430,15 @@ checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760"
 
 [[package]]
 name = "libc"
-version = "0.2.155"
+version = "0.2.171"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
+checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
 
 [[package]]
 name = "libffi"
-version = "3.2.0"
+version = "4.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce826c243048e3d5cec441799724de52e2d42f820468431fc3fceee2341871e2"
+checksum = "4a9434b6fc77375fb624698d5f8c49d7e80b10d59eb1219afda27d1f824d4074"
 dependencies = [
  "libc",
  "libffi-sys",
@@ -445,21 +446,21 @@ dependencies = [
 
 [[package]]
 name = "libffi-sys"
-version = "2.3.0"
+version = "3.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f36115160c57e8529781b4183c2bb51fdc1f6d6d1ed345591d84be7703befb3c"
+checksum = "ead36a2496acfc8edd6cc32352110e9478ac5b9b5f5b9856ebd3d28019addb84"
 dependencies = [
  "cc",
 ]
 
 [[package]]
 name = "libloading"
-version = "0.8.5"
+version = "0.8.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
+checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
 dependencies = [
  "cfg-if",
- "windows-targets 0.52.6",
+ "windows-targets",
 ]
 
 [[package]]
@@ -474,9 +475,9 @@ dependencies = [
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.14"
+version = "0.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
 
 [[package]]
 name = "lock_api"
@@ -490,15 +491,15 @@ dependencies = [
 
 [[package]]
 name = "log"
-version = "0.4.22"
+version = "0.4.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
 
 [[package]]
 name = "measureme"
-version = "11.0.1"
+version = "12.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfa4a40f09af7aa6faef38285402a78847d0d72bf8827006cd2a332e1e6e4a8d"
+checksum = "570a507d8948a66a97f42cbbaf8a6bb9516a51017d4ee949502ad7a10a864395"
 dependencies = [
  "log",
  "memmap2",
@@ -537,11 +538,12 @@ name = "miri"
 version = "0.1.0"
 dependencies = [
  "aes",
+ "bitflags",
  "chrono",
  "chrono-tz",
  "colored",
  "directories",
- "getrandom 0.3.1",
+ "getrandom 0.3.2",
  "libc",
  "libffi",
  "libloading",
@@ -553,7 +555,7 @@ dependencies = [
  "tempfile",
  "tikv-jemalloc-sys",
  "ui_test",
- "windows-sys 0.52.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -582,9 +584,9 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.19.0"
+version = "1.21.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
 
 [[package]]
 name = "option-ext"
@@ -604,7 +606,7 @@ version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d2ad9b889f1b12e0b9ee24db044b5129150d5eada288edc800f789928dc8c0e3"
 dependencies = [
- "unicode-width",
+ "unicode-width 0.1.14",
 ]
 
 [[package]]
@@ -627,7 +629,7 @@ dependencies = [
  "libc",
  "redox_syscall",
  "smallvec",
- "windows-targets 0.52.6",
+ "windows-targets",
 ]
 
 [[package]]
@@ -650,18 +652,18 @@ dependencies = [
 
 [[package]]
 name = "phf"
-version = "0.11.2"
+version = "0.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
+checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
 dependencies = [
  "phf_shared",
 ]
 
 [[package]]
 name = "phf_codegen"
-version = "0.11.2"
+version = "0.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a"
+checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a"
 dependencies = [
  "phf_generator",
  "phf_shared",
@@ -669,9 +671,9 @@ dependencies = [
 
 [[package]]
 name = "phf_generator"
-version = "0.11.2"
+version = "0.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
+checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
 dependencies = [
  "phf_shared",
  "rand 0.8.5",
@@ -679,32 +681,32 @@ dependencies = [
 
 [[package]]
 name = "phf_shared"
-version = "0.11.2"
+version = "0.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
+checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
 dependencies = [
  "siphasher",
 ]
 
 [[package]]
 name = "pin-project-lite"
-version = "0.2.14"
+version = "0.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
+checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
 
 [[package]]
 name = "portable-atomic"
-version = "1.7.0"
+version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265"
+checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
 
 [[package]]
 name = "ppv-lite86"
-version = "0.2.20"
+version = "0.2.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
 dependencies = [
- "zerocopy 0.7.35",
+ "zerocopy",
 ]
 
 [[package]]
@@ -719,23 +721,29 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.86"
+version = "1.0.94"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.36"
+version = "1.0.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
 dependencies = [
  "proc-macro2",
 ]
 
 [[package]]
+name = "r-efi"
+version = "5.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
+
+[[package]]
 name = "rand"
 version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -751,8 +759,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
 dependencies = [
  "rand_chacha",
- "rand_core 0.9.0",
- "zerocopy 0.8.14",
+ "rand_core 0.9.3",
+ "zerocopy",
 ]
 
 [[package]]
@@ -762,7 +770,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
 dependencies = [
  "ppv-lite86",
- "rand_core 0.9.0",
+ "rand_core 0.9.3",
 ]
 
 [[package]]
@@ -773,39 +781,38 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
 
 [[package]]
 name = "rand_core"
-version = "0.9.0"
+version = "0.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff"
+checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
 dependencies = [
- "getrandom 0.3.1",
- "zerocopy 0.8.14",
+ "getrandom 0.3.2",
 ]
 
 [[package]]
 name = "redox_syscall"
-version = "0.5.3"
+version = "0.5.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
+checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1"
 dependencies = [
  "bitflags",
 ]
 
 [[package]]
 name = "redox_users"
-version = "0.4.5"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891"
+checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
 dependencies = [
  "getrandom 0.2.15",
  "libredox",
- "thiserror",
+ "thiserror 2.0.12",
 ]
 
 [[package]]
 name = "regex"
-version = "1.10.6"
+version = "1.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -815,9 +822,9 @@ dependencies = [
 
 [[package]]
 name = "regex-automata"
-version = "0.4.7"
+version = "0.4.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -826,9 +833,9 @@ dependencies = [
 
 [[package]]
 name = "regex-syntax"
-version = "0.8.4"
+version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
 
 [[package]]
 name = "rustc-demangle"
@@ -844,43 +851,43 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
 
 [[package]]
 name = "rustc_version"
-version = "0.4.0"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
 dependencies = [
  "semver",
 ]
 
 [[package]]
 name = "rustfix"
-version = "0.8.5"
+version = "0.8.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70f5b7fc8060f4f8373f9381a630304b42e1183535d9beb1d3f596b236c9106a"
+checksum = "82fa69b198d894d84e23afde8e9ab2af4400b2cba20d6bf2b428a8b01c222c5a"
 dependencies = [
  "serde",
  "serde_json",
- "thiserror",
+ "thiserror 1.0.69",
  "tracing",
 ]
 
 [[package]]
 name = "rustix"
-version = "0.38.34"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
+checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
 dependencies = [
  "bitflags",
  "errno",
  "libc",
  "linux-raw-sys",
- "windows-sys 0.52.0",
+ "windows-sys",
 ]
 
 [[package]]
 name = "ryu"
-version = "1.0.18"
+version = "1.0.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
 
 [[package]]
 name = "scopeguard"
@@ -890,27 +897,27 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
 [[package]]
 name = "semver"
-version = "1.0.23"
+version = "1.0.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
+checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "serde"
-version = "1.0.204"
+version = "1.0.219"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
+checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.204"
+version = "1.0.219"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
+checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -919,9 +926,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.122"
+version = "1.0.140"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da"
+checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
 dependencies = [
  "itoa",
  "memchr",
@@ -946,15 +953,15 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
 
 [[package]]
 name = "siphasher"
-version = "0.3.11"
+version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
+checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
 
 [[package]]
 name = "smallvec"
-version = "1.13.2"
+version = "1.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
+checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
 
 [[package]]
 name = "spanned"
@@ -968,9 +975,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.72"
+version = "2.0.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
+checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -979,31 +986,51 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.11.0"
+version = "3.19.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53"
+checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf"
 dependencies = [
- "cfg-if",
  "fastrand",
+ "getrandom 0.3.2",
  "once_cell",
  "rustix",
- "windows-sys 0.52.0",
+ "windows-sys",
 ]
 
 [[package]]
 name = "thiserror"
-version = "1.0.63"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+dependencies = [
+ "thiserror-impl 1.0.69",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
+dependencies = [
+ "thiserror-impl 2.0.12",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.69"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
 dependencies = [
- "thiserror-impl",
+ "proc-macro2",
+ "quote",
+ "syn",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.63"
+version = "2.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
+checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1032,9 +1059,9 @@ dependencies = [
 
 [[package]]
 name = "tracing"
-version = "0.1.40"
+version = "0.1.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
+checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
 dependencies = [
  "pin-project-lite",
  "tracing-core",
@@ -1042,9 +1069,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-core"
-version = "0.1.32"
+version = "0.1.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
+checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
 dependencies = [
  "once_cell",
  "valuable",
@@ -1052,9 +1079,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-error"
-version = "0.2.0"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e"
+checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db"
 dependencies = [
  "tracing",
  "tracing-subscriber",
@@ -1062,9 +1089,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-subscriber"
-version = "0.3.18"
+version = "0.3.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
+checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
 dependencies = [
  "sharded-slab",
  "thread_local",
@@ -1073,15 +1100,15 @@ dependencies = [
 
 [[package]]
 name = "typenum"
-version = "1.17.0"
+version = "1.18.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
+checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
 
 [[package]]
 name = "ui_test"
-version = "0.29.1"
+version = "0.29.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14bf63f2931a28a04af0bd24c5f850223d29f3a40afae49ed6ce442a65eb8652"
+checksum = "1211b1111c752c73b33073d2958072be08825fd97c9ab4d83444da361a06634b"
 dependencies = [
  "annotate-snippets",
  "anyhow",
@@ -1105,21 +1132,27 @@ dependencies = [
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.12"
+version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
 
 [[package]]
 name = "unicode-width"
-version = "0.1.13"
+version = "0.1.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
+checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
+
+[[package]]
+name = "unicode-width"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
 
 [[package]]
 name = "valuable"
-version = "0.1.0"
+version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
+checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
 
 [[package]]
 name = "version_check"
@@ -1135,91 +1168,116 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasi"
-version = "0.13.3+wasi-0.2.2"
+version = "0.14.2+wasi-0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
+checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
 dependencies = [
  "wit-bindgen-rt",
 ]
 
 [[package]]
-name = "windows-sys"
-version = "0.48.0"
+name = "wasm-bindgen"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
 dependencies = [
- "windows-targets 0.48.5",
+ "cfg-if",
+ "once_cell",
+ "wasm-bindgen-macro",
 ]
 
 [[package]]
-name = "windows-sys"
-version = "0.52.0"
+name = "wasm-bindgen-backend"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
 dependencies = [
- "windows-targets 0.52.6",
+ "bumpalo",
+ "log",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
 ]
 
 [[package]]
-name = "windows-targets"
-version = "0.48.5"
+name = "wasm-bindgen-macro"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
 dependencies = [
- "windows_aarch64_gnullvm 0.48.5",
- "windows_aarch64_msvc 0.48.5",
- "windows_i686_gnu 0.48.5",
- "windows_i686_msvc 0.48.5",
- "windows_x86_64_gnu 0.48.5",
- "windows_x86_64_gnullvm 0.48.5",
- "windows_x86_64_msvc 0.48.5",
+ "quote",
+ "wasm-bindgen-macro-support",
 ]
 
 [[package]]
-name = "windows-targets"
-version = "0.52.6"
+name = "wasm-bindgen-macro-support"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
 dependencies = [
- "windows_aarch64_gnullvm 0.52.6",
- "windows_aarch64_msvc 0.52.6",
- "windows_i686_gnu 0.52.6",
- "windows_i686_gnullvm",
- "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",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
 ]
 
 [[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.48.5"
+name = "wasm-bindgen-shared"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+dependencies = [
+ "unicode-ident",
+]
 
 [[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.52.6"
+name = "web-time"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
 
 [[package]]
-name = "windows_aarch64_msvc"
-version = "0.48.5"
+name = "windows-sys"
+version = "0.59.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
 
 [[package]]
-name = "windows_aarch64_msvc"
+name = "windows-targets"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+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",
+]
 
 [[package]]
-name = "windows_i686_gnu"
-version = "0.48.5"
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 
 [[package]]
 name = "windows_i686_gnu"
@@ -1235,96 +1293,51 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
-
-[[package]]
-name = "windows_i686_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
-
-[[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_gnullvm"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
-
-[[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_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
-
-[[package]]
-name = "windows_x86_64_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
 name = "wit-bindgen-rt"
-version = "0.33.0"
+version = "0.39.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
+checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
 dependencies = [
  "bitflags",
 ]
 
 [[package]]
 name = "zerocopy"
-version = "0.7.35"
+version = "0.8.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
+checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879"
 dependencies = [
- "byteorder",
- "zerocopy-derive 0.7.35",
-]
-
-[[package]]
-name = "zerocopy"
-version = "0.8.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a367f292d93d4eab890745e75a778da40909cab4d6ff8173693812f79c4a2468"
-dependencies = [
- "zerocopy-derive 0.8.14",
-]
-
-[[package]]
-name = "zerocopy-derive"
-version = "0.7.35"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
+ "zerocopy-derive",
 ]
 
 [[package]]
 name = "zerocopy-derive"
-version = "0.8.14"
+version = "0.8.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3931cb58c62c13adec22e38686b559c86a30565e16ad6e8510a337cedc611e1"
+checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be"
 dependencies = [
  "proc-macro2",
  "quote",
diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml
index 5d8c9a86644..bb24e700e73 100644
--- a/src/tools/miri/Cargo.toml
+++ b/src/tools/miri/Cargo.toml
@@ -22,10 +22,11 @@ getrandom = { version = "0.3", features = ["std"] }
 rand = "0.9"
 smallvec = { version = "1.7", features = ["drain_filter"] }
 aes = { version = "0.8.3", features = ["hazmat"] }
-measureme = "11"
+measureme = "12"
 chrono = { version = "0.4.38", default-features = false }
 chrono-tz = "0.10"
-directories = "5"
+directories = "6"
+bitflags = "2.6"
 
 # 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
@@ -36,11 +37,11 @@ features = ['unprefixed_malloc_on_supported_platforms']
 
 [target.'cfg(unix)'.dependencies]
 libc = "0.2"
-libffi = "3.2.0"
+libffi = "4.0.0"
 libloading = "0.8"
 
 [target.'cfg(target_family = "windows")'.dependencies]
-windows-sys = { version = "0.52", features = [
+windows-sys = { version = "0.59", features = [
     "Win32_Foundation",
     "Win32_System_IO",
     "Win32_Storage_FileSystem",
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index 201aa1f5386..e8ea988558c 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -565,6 +565,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)
 
 Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment):
 
diff --git a/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs b/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs
index a1c1708cf3b..5b807ac3df1 100644
--- a/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs
+++ b/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs
@@ -7,7 +7,10 @@ fn main() {
     // We can't use too big of an allocation or this code will encounter an allocation failure in
     // CI. Since the allocation can't be huge, we need to do a few iterations so that the effect
     // we're trying to measure is clearly visible above the interpreter's startup time.
-    for _ in 0..10 {
+    // FIXME (https://github.com/rust-lang/miri/issues/4253): On 32bit targets, we can run out of
+    // usable addresses if we don't reuse, leading to random test failures.
+    let count = if cfg!(target_pointer_width = "32") { 8 } else { 12 };
+    for _ in 0..count {
         drop(Vec::<u8>::with_capacity(512 * 1024 * 1024));
     }
 }
diff --git a/src/tools/miri/cargo-miri/Cargo.lock b/src/tools/miri/cargo-miri/Cargo.lock
index b8e08d39a86..bd4ca2860f3 100644
--- a/src/tools/miri/cargo-miri/Cargo.lock
+++ b/src/tools/miri/cargo-miri/Cargo.lock
@@ -4,21 +4,21 @@ version = 4
 
 [[package]]
 name = "anyhow"
-version = "1.0.86"
+version = "1.0.97"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
+checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
 
 [[package]]
 name = "bitflags"
-version = "2.6.0"
+version = "2.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
 
 [[package]]
 name = "camino"
-version = "1.1.7"
+version = "1.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239"
+checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3"
 dependencies = [
  "serde",
 ]
@@ -38,18 +38,18 @@ dependencies = [
 
 [[package]]
 name = "cargo-platform"
-version = "0.1.8"
+version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc"
+checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "cargo_metadata"
-version = "0.18.1"
+version = "0.19.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037"
+checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba"
 dependencies = [
  "camino",
  "cargo-platform",
@@ -67,40 +67,40 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "directories"
-version = "5.0.1"
+version = "6.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35"
+checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d"
 dependencies = [
  "dirs-sys",
 ]
 
 [[package]]
 name = "dirs-sys"
-version = "0.4.1"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
+checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
 dependencies = [
  "libc",
  "option-ext",
  "redox_users",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
 name = "errno"
-version = "0.3.9"
+version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
+checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
 dependencies = [
  "libc",
- "windows-sys 0.52.0",
+ "windows-sys",
 ]
 
 [[package]]
 name = "fastrand"
-version = "2.1.0"
+version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
 
 [[package]]
 name = "getrandom"
@@ -110,20 +110,32 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
 dependencies = [
  "cfg-if",
  "libc",
- "wasi",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "wasi 0.14.2+wasi-0.2.4",
 ]
 
 [[package]]
 name = "itoa"
-version = "1.0.11"
+version = "1.0.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
 
 [[package]]
 name = "libc"
-version = "0.2.155"
+version = "0.2.171"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
+checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
 
 [[package]]
 name = "libredox"
@@ -137,9 +149,9 @@ dependencies = [
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.14"
+version = "0.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
 
 [[package]]
 name = "memchr"
@@ -149,9 +161,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 
 [[package]]
 name = "once_cell"
-version = "1.19.0"
+version = "1.21.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
 
 [[package]]
 name = "option-ext"
@@ -161,29 +173,35 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.86"
+version = "1.0.94"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.36"
+version = "1.0.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
 dependencies = [
  "proc-macro2",
 ]
 
 [[package]]
+name = "r-efi"
+version = "5.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
+
+[[package]]
 name = "redox_users"
-version = "0.4.5"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891"
+checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
 dependencies = [
- "getrandom",
+ "getrandom 0.2.15",
  "libredox",
  "thiserror",
 ]
@@ -202,37 +220,37 @@ dependencies = [
 
 [[package]]
 name = "rustc_tools_util"
-version = "0.4.0"
+version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3316159ab19e19d1065ecc49278e87f767a9dae9fae80348d2b4d4fa4ae02d4d"
+checksum = "a3b75158011a63889ba12084cf1224baad7bcad50f6ee7c842f772b74aa148ed"
 
 [[package]]
 name = "rustc_version"
-version = "0.4.0"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
 dependencies = [
  "semver",
 ]
 
 [[package]]
 name = "rustix"
-version = "0.38.34"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
+checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
 dependencies = [
  "bitflags",
  "errno",
  "libc",
  "linux-raw-sys",
- "windows-sys 0.52.0",
+ "windows-sys",
 ]
 
 [[package]]
 name = "ryu"
-version = "1.0.18"
+version = "1.0.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
 
 [[package]]
 name = "same-file"
@@ -245,27 +263,27 @@ dependencies = [
 
 [[package]]
 name = "semver"
-version = "1.0.23"
+version = "1.0.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
+checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "serde"
-version = "1.0.204"
+version = "1.0.219"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
+checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.204"
+version = "1.0.219"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
+checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -274,9 +292,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.122"
+version = "1.0.140"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da"
+checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
 dependencies = [
  "itoa",
  "memchr",
@@ -286,9 +304,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.72"
+version = "2.0.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
+checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -297,31 +315,31 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.11.0"
+version = "3.19.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53"
+checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf"
 dependencies = [
- "cfg-if",
  "fastrand",
+ "getrandom 0.3.2",
  "once_cell",
  "rustix",
- "windows-sys 0.52.0",
+ "windows-sys",
 ]
 
 [[package]]
 name = "thiserror"
-version = "1.0.63"
+version = "2.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
+checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.63"
+version = "2.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
+checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -330,9 +348,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.12"
+version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
 
 [[package]]
 name = "walkdir"
@@ -351,30 +369,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
-name = "winapi-util"
-version = "0.1.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
-dependencies = [
- "windows-sys 0.59.0",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.48.0"
+name = "wasi"
+version = "0.14.2+wasi-0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
 dependencies = [
- "windows-targets 0.48.5",
+ "wit-bindgen-rt",
 ]
 
 [[package]]
-name = "windows-sys"
-version = "0.52.0"
+name = "winapi-util"
+version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
 dependencies = [
- "windows-targets 0.52.6",
+ "windows-sys",
 ]
 
 [[package]]
@@ -383,22 +392,7 @@ version = "0.59.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
 dependencies = [
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
-dependencies = [
- "windows_aarch64_gnullvm 0.48.5",
- "windows_aarch64_msvc 0.48.5",
- "windows_i686_gnu 0.48.5",
- "windows_i686_msvc 0.48.5",
- "windows_x86_64_gnu 0.48.5",
- "windows_x86_64_gnullvm 0.48.5",
- "windows_x86_64_msvc 0.48.5",
+ "windows-targets",
 ]
 
 [[package]]
@@ -407,48 +401,30 @@ version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
 dependencies = [
- "windows_aarch64_gnullvm 0.52.6",
- "windows_aarch64_msvc 0.52.6",
- "windows_i686_gnu 0.52.6",
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
  "windows_i686_gnullvm",
- "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",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
 ]
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
-
-[[package]]
-name = "windows_aarch64_gnullvm"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
-
-[[package]]
-name = "windows_aarch64_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
-
-[[package]]
-name = "windows_i686_gnu"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
@@ -461,48 +437,33 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
-
-[[package]]
-name = "windows_i686_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
-
-[[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_gnullvm"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
-
-[[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_msvc"
-version = "0.48.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
-name = "windows_x86_64_msvc"
-version = "0.52.6"
+name = "wit-bindgen-rt"
+version = "0.39.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
+dependencies = [
+ "bitflags",
+]
diff --git a/src/tools/miri/cargo-miri/Cargo.toml b/src/tools/miri/cargo-miri/Cargo.toml
index de0988d6d1c..ed142b0e211 100644
--- a/src/tools/miri/cargo-miri/Cargo.toml
+++ b/src/tools/miri/cargo-miri/Cargo.toml
@@ -14,10 +14,10 @@ test = false # we have no unit tests
 doctest = false # and no doc tests
 
 [dependencies]
-directories = "5"
+directories = "6"
 rustc_version = "0.4"
 serde_json = "1.0.40"
-cargo_metadata = "0.18.0"
+cargo_metadata = "0.19"
 rustc-build-sysroot = "0.5.4"
 
 # Enable some feature flags that dev-dependencies need but dependencies
diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh
index 7155d692ee5..755e02d02ec 100755
--- a/src/tools/miri/ci/ci.sh
+++ b/src/tools/miri/ci/ci.sh
@@ -164,9 +164,9 @@ case $HOST_TARGET in
     # Partially supported targets (tier 2)
     BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator
     UNIX="hello panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there
-    TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe
-    TEST_TARGET=i686-unknown-freebsd   run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe
-    TEST_TARGET=aarch64-linux-android  run_tests_minimal $BASIC $UNIX time hashmap random sync concurrency thread epoll eventfd
+    TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency fs libc-pipe
+    TEST_TARGET=i686-unknown-freebsd   run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency fs libc-pipe
+    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
diff --git a/src/tools/miri/miri-script/Cargo.lock b/src/tools/miri/miri-script/Cargo.lock
index 25c6f817575..3494a241ec5 100644
--- a/src/tools/miri/miri-script/Cargo.lock
+++ b/src/tools/miri/miri-script/Cargo.lock
@@ -38,30 +38,31 @@ version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
 dependencies = [
- "windows-sys 0.59.0",
+ "windows-sys",
 ]
 
 [[package]]
 name = "anstyle-wincon"
-version = "3.0.6"
+version = "3.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
+checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
 dependencies = [
  "anstyle",
- "windows-sys 0.59.0",
+ "once_cell",
+ "windows-sys",
 ]
 
 [[package]]
 name = "anyhow"
-version = "1.0.80"
+version = "1.0.97"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
+checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
 
 [[package]]
 name = "bitflags"
-version = "2.4.2"
+version = "2.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
+checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
 
 [[package]]
 name = "cfg-if"
@@ -71,9 +72,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "clap"
-version = "4.5.23"
+version = "4.5.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84"
+checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -81,9 +82,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.23"
+version = "4.5.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838"
+checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9"
 dependencies = [
  "anstream",
  "anstyle",
@@ -93,9 +94,9 @@ dependencies = [
 
 [[package]]
 name = "clap_derive"
-version = "4.5.18"
+version = "4.5.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
+checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
 dependencies = [
  "heck",
  "proc-macro2",
@@ -117,78 +118,87 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
 
 [[package]]
 name = "directories"
-version = "5.0.1"
+version = "6.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35"
+checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d"
 dependencies = [
  "dirs-sys",
 ]
 
 [[package]]
 name = "dirs-sys"
-version = "0.4.1"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
+checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
 dependencies = [
  "libc",
  "option-ext",
  "redox_users",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
 name = "dunce"
-version = "1.0.4"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b"
+checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
 
 [[package]]
 name = "either"
-version = "1.10.0"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+
+[[package]]
+name = "env_home"
+version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
+checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe"
 
 [[package]]
 name = "errno"
-version = "0.3.9"
+version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
+checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
 dependencies = [
  "libc",
- "windows-sys 0.52.0",
+ "windows-sys",
 ]
 
 [[package]]
 name = "fastrand"
-version = "2.1.1"
+version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
 
 [[package]]
 name = "getrandom"
-version = "0.2.12"
+version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
 dependencies = [
  "cfg-if",
  "libc",
- "wasi",
+ "wasi 0.11.0+wasi-snapshot-preview1",
 ]
 
 [[package]]
-name = "heck"
-version = "0.5.0"
+name = "getrandom"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "wasi 0.14.2+wasi-0.2.4",
+]
 
 [[package]]
-name = "home"
-version = "0.5.9"
+name = "heck"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
-dependencies = [
- "windows-sys 0.52.0",
-]
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
 
 [[package]]
 name = "is_terminal_polyfill"
@@ -198,24 +208,24 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
 
 [[package]]
 name = "itertools"
-version = "0.11.0"
+version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
+checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
 dependencies = [
  "either",
 ]
 
 [[package]]
 name = "itoa"
-version = "1.0.11"
+version = "1.0.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
 
 [[package]]
 name = "libc"
-version = "0.2.159"
+version = "0.2.171"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
+checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
 
 [[package]]
 name = "libredox"
@@ -229,9 +239,15 @@ dependencies = [
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.14"
+version = "0.4.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
 
 [[package]]
 name = "memchr"
@@ -262,9 +278,9 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.20.2"
+version = "1.21.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
 
 [[package]]
 name = "option-ext"
@@ -280,60 +296,79 @@ checksum = "a6e819bbd49d5939f682638fa54826bf1650abddcd65d000923de8ad63cc7d15"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.78"
+version = "1.0.94"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
+checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.35"
+version = "1.0.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
 dependencies = [
  "proc-macro2",
 ]
 
 [[package]]
+name = "r-efi"
+version = "5.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
+
+[[package]]
 name = "redox_users"
-version = "0.4.6"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
+checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
 dependencies = [
- "getrandom",
+ "getrandom 0.2.15",
  "libredox",
  "thiserror",
 ]
 
 [[package]]
 name = "rustc_version"
-version = "0.4.0"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
 dependencies = [
  "semver",
 ]
 
 [[package]]
 name = "rustix"
-version = "0.38.37"
+version = "0.38.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
+dependencies = [
+ "bitflags",
+ "errno",
+ "libc",
+ "linux-raw-sys 0.4.15",
+ "windows-sys",
+]
+
+[[package]]
+name = "rustix"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
+checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
 dependencies = [
  "bitflags",
  "errno",
  "libc",
- "linux-raw-sys",
- "windows-sys 0.52.0",
+ "linux-raw-sys 0.9.3",
+ "windows-sys",
 ]
 
 [[package]]
 name = "ryu"
-version = "1.0.18"
+version = "1.0.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
 
 [[package]]
 name = "same-file"
@@ -346,24 +381,24 @@ dependencies = [
 
 [[package]]
 name = "semver"
-version = "1.0.22"
+version = "1.0.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
+checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
 
 [[package]]
 name = "serde"
-version = "1.0.210"
+version = "1.0.219"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
+checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.210"
+version = "1.0.219"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
+checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -372,9 +407,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.128"
+version = "1.0.140"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
+checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
 dependencies = [
  "itoa",
  "memchr",
@@ -396,9 +431,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
 
 [[package]]
 name = "syn"
-version = "2.0.50"
+version = "2.0.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb"
+checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -407,31 +442,31 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.13.0"
+version = "3.19.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
+checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf"
 dependencies = [
- "cfg-if",
  "fastrand",
+ "getrandom 0.3.2",
  "once_cell",
- "rustix",
- "windows-sys 0.59.0",
+ "rustix 1.0.5",
+ "windows-sys",
 ]
 
 [[package]]
 name = "thiserror"
-version = "1.0.57"
+version = "2.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
+checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.57"
+version = "2.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
+checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -440,9 +475,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.12"
+version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
 
 [[package]]
 name = "utf8parse"
@@ -452,9 +487,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
 
 [[package]]
 name = "walkdir"
-version = "2.4.0"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
 dependencies = [
  "same-file",
  "winapi-util",
@@ -467,14 +502,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
+name = "wasi"
+version = "0.14.2+wasi-0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
+dependencies = [
+ "wit-bindgen-rt",
+]
+
+[[package]]
 name = "which"
-version = "6.0.3"
+version = "7.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f"
+checksum = "2774c861e1f072b3aadc02f8ba886c26ad6321567ecc294c935434cad06f1283"
 dependencies = [
  "either",
- "home",
- "rustix",
+ "env_home",
+ "rustix 0.38.44",
  "winsafe",
 ]
 
@@ -484,25 +528,7 @@ version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
 dependencies = [
- "windows-sys 0.59.0",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
-dependencies = [
- "windows-targets 0.48.5",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
-dependencies = [
- "windows-targets 0.52.6",
+ "windows-sys",
 ]
 
 [[package]]
@@ -511,22 +537,7 @@ version = "0.59.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
 dependencies = [
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
-dependencies = [
- "windows_aarch64_gnullvm 0.48.5",
- "windows_aarch64_msvc 0.48.5",
- "windows_i686_gnu 0.48.5",
- "windows_i686_msvc 0.48.5",
- "windows_x86_64_gnu 0.48.5",
- "windows_x86_64_gnullvm 0.48.5",
- "windows_x86_64_msvc 0.48.5",
+ "windows-targets",
 ]
 
 [[package]]
@@ -535,48 +546,30 @@ version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
 dependencies = [
- "windows_aarch64_gnullvm 0.52.6",
- "windows_aarch64_msvc 0.52.6",
- "windows_i686_gnu 0.52.6",
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
  "windows_i686_gnullvm",
- "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",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
 ]
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
-
-[[package]]
-name = "windows_aarch64_gnullvm"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
-
-[[package]]
-name = "windows_aarch64_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
-
-[[package]]
-name = "windows_i686_gnu"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
@@ -589,48 +582,24 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
-
-[[package]]
-name = "windows_i686_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
-
-[[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_gnullvm"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
-
-[[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_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
-
-[[package]]
-name = "windows_x86_64_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
@@ -642,6 +611,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
 
 [[package]]
+name = "wit-bindgen-rt"
+version = "0.39.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
 name = "xshell"
 version = "0.2.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/miri/miri-script/Cargo.toml b/src/tools/miri/miri-script/Cargo.toml
index 5879b2717e5..a04898de6ab 100644
--- a/src/tools/miri/miri-script/Cargo.toml
+++ b/src/tools/miri/miri-script/Cargo.toml
@@ -13,16 +13,16 @@ edition = "2021"
 # This is needed to make this package build on stable when the parent package uses unstable cargo features.
 
 [dependencies]
-which = "6.0"
+which = "7"
 walkdir = "2.3"
-itertools = "0.11"
+itertools = "0.14"
 path_macro = "1.0"
 shell-words = "1.1"
 anyhow = "1.0"
 xshell = "0.2.6"
 rustc_version = "0.4"
 dunce = "1.0.4"
-directories = "5"
+directories = "6"
 serde = "1"
 serde_json = "1"
 serde_derive = "1"
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index cf36b6fd038..d1107e51509 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-4ac032f857b46037b55c1fc0fa702450aad37f43
+1bc56185ee257ed829a0aea7abdc3b03c5fed887
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 56ee96502b3..4e8fe0ca8ad 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -185,7 +185,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
             let num_failed = sync::IntoDynSyncSend(AtomicU32::new(0));
             sync::par_for_each_in(many_seeds.seeds.clone(), |seed| {
                 let mut config = config.clone();
-                config.seed = Some(seed.into());
+                config.seed = Some((*seed).into());
                 eprintln!("Trying seed: {seed}");
                 let return_code = miri::eval_entry(tcx, entry_def_id, entry_type, config)
                     .unwrap_or(rustc_driver::EXIT_FAILURE);
diff --git a/src/tools/miri/src/clock.rs b/src/tools/miri/src/clock.rs
index c9bffc449f7..34465e9cac6 100644
--- a/src/tools/miri/src/clock.rs
+++ b/src/tools/miri/src/clock.rs
@@ -62,12 +62,12 @@ impl Instant {
 
 /// A monotone clock used for `Instant` simulation.
 #[derive(Debug)]
-pub struct Clock {
-    kind: ClockKind,
+pub struct MonotonicClock {
+    kind: MonotonicClockKind,
 }
 
 #[derive(Debug)]
-enum ClockKind {
+enum MonotonicClockKind {
     Host {
         /// The "epoch" for this machine's monotone clock:
         /// the moment we consider to be time = 0.
@@ -79,13 +79,13 @@ enum ClockKind {
     },
 }
 
-impl Clock {
+impl MonotonicClock {
     /// Create a new clock based on the availability of communication with the host.
     pub fn new(communicate: bool) -> Self {
         let kind = if communicate {
-            ClockKind::Host { epoch: StdInstant::now() }
+            MonotonicClockKind::Host { epoch: StdInstant::now() }
         } else {
-            ClockKind::Virtual { nanoseconds: 0.into() }
+            MonotonicClockKind::Virtual { nanoseconds: 0.into() }
         };
 
         Self { kind }
@@ -94,10 +94,10 @@ impl Clock {
     /// Let the time pass for a small interval.
     pub fn tick(&self) {
         match &self.kind {
-            ClockKind::Host { .. } => {
+            MonotonicClockKind::Host { .. } => {
                 // Time will pass without us doing anything.
             }
-            ClockKind::Virtual { nanoseconds } => {
+            MonotonicClockKind::Virtual { nanoseconds } => {
                 nanoseconds.update(|x| x + NANOSECONDS_PER_BASIC_BLOCK);
             }
         }
@@ -106,8 +106,8 @@ impl Clock {
     /// Sleep for the desired duration.
     pub fn sleep(&self, duration: Duration) {
         match &self.kind {
-            ClockKind::Host { .. } => std::thread::sleep(duration),
-            ClockKind::Virtual { nanoseconds } => {
+            MonotonicClockKind::Host { .. } => std::thread::sleep(duration),
+            MonotonicClockKind::Virtual { nanoseconds } => {
                 // Just pretend that we have slept for some time.
                 let nanos: u128 = duration.as_nanos();
                 nanoseconds.update(|x| {
@@ -121,15 +121,17 @@ impl Clock {
     /// Return the `epoch` instant (time = 0), to convert between monotone instants and absolute durations.
     pub fn epoch(&self) -> Instant {
         match &self.kind {
-            ClockKind::Host { epoch } => Instant { kind: InstantKind::Host(*epoch) },
-            ClockKind::Virtual { .. } => Instant { kind: InstantKind::Virtual { nanoseconds: 0 } },
+            MonotonicClockKind::Host { epoch } => Instant { kind: InstantKind::Host(*epoch) },
+            MonotonicClockKind::Virtual { .. } =>
+                Instant { kind: InstantKind::Virtual { nanoseconds: 0 } },
         }
     }
 
     pub fn now(&self) -> Instant {
         match &self.kind {
-            ClockKind::Host { .. } => Instant { kind: InstantKind::Host(StdInstant::now()) },
-            ClockKind::Virtual { nanoseconds } =>
+            MonotonicClockKind::Host { .. } =>
+                Instant { kind: InstantKind::Host(StdInstant::now()) },
+            MonotonicClockKind::Virtual { nanoseconds } =>
                 Instant { kind: InstantKind::Virtual { nanoseconds: nanoseconds.get() } },
         }
     }
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index 94629964ea6..72fa918e8e5 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -347,7 +347,7 @@ enum Timeout {
 
 impl Timeout {
     /// How long do we have to wait from now until the specified time?
-    fn get_wait_time(&self, clock: &Clock) -> Duration {
+    fn get_wait_time(&self, clock: &MonotonicClock) -> Duration {
         match self {
             Timeout::Monotonic(instant) => instant.duration_since(clock.now()),
             Timeout::RealTime(time) =>
@@ -683,7 +683,7 @@ impl<'tcx> ThreadManager<'tcx> {
     }
 
     /// Get the wait time for the next timeout, or `None` if no timeout is pending.
-    fn next_callback_wait_time(&self, clock: &Clock) -> Option<Duration> {
+    fn next_callback_wait_time(&self, clock: &MonotonicClock) -> Option<Duration> {
         self.threads
             .iter()
             .filter_map(|t| {
@@ -702,7 +702,7 @@ impl<'tcx> ThreadManager<'tcx> {
     /// used in stateless model checkers such as Loom: run the active thread as
     /// long as we can and switch only when we have to (the active thread was
     /// blocked, terminated, or has explicitly asked to be preempted).
-    fn schedule(&mut self, clock: &Clock) -> InterpResult<'tcx, SchedulingAction> {
+    fn schedule(&mut self, clock: &MonotonicClock) -> InterpResult<'tcx, SchedulingAction> {
         // This thread and the program can keep going.
         if self.threads[self.active_thread].state.is_enabled() && !self.yield_active_thread {
             // The currently active thread is still enabled, just continue with it.
@@ -772,7 +772,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
         for (id, thread) in this.machine.threads.threads.iter_enumerated_mut() {
             match &thread.state {
                 ThreadState::Blocked { timeout: Some(timeout), .. }
-                    if timeout.get_wait_time(&this.machine.clock) == Duration::ZERO =>
+                    if timeout.get_wait_time(&this.machine.monotonic_clock) == Duration::ZERO =>
                 {
                     let old_state = mem::replace(&mut thread.state, ThreadState::Enabled);
                     let ThreadState::Blocked { callback, .. } = old_state else { unreachable!() };
@@ -1006,8 +1006,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 }
                 TimeoutClock::Monotonic =>
                     Timeout::Monotonic(match anchor {
-                        TimeoutAnchor::Absolute => this.machine.clock.epoch(),
-                        TimeoutAnchor::Relative => this.machine.clock.now(),
+                        TimeoutAnchor::Absolute => this.machine.monotonic_clock.epoch(),
+                        TimeoutAnchor::Relative => this.machine.monotonic_clock.now(),
                     }),
             };
             anchor.add_lossy(duration)
@@ -1152,7 +1152,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.machine.handle_abnormal_termination();
                 throw_machine_stop!(TerminationInfo::Interrupted);
             }
-            match this.machine.threads.schedule(&this.machine.clock)? {
+            match this.machine.threads.schedule(&this.machine.monotonic_clock)? {
                 SchedulingAction::ExecuteStep => {
                     if !this.step()? {
                         // See if this thread can do something else.
@@ -1167,7 +1167,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     this.run_timeout_callback()?;
                 }
                 SchedulingAction::Sleep(duration) => {
-                    this.machine.clock.sleep(duration);
+                    this.machine.monotonic_clock.sleep(duration);
                 }
             }
         }
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index ed13f670a90..7586b5efd4b 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -459,8 +459,13 @@ pub fn eval_entry<'tcx>(
         ecx.handle_ice();
         panic::resume_unwind(panic_payload)
     });
-    // `Ok` can never happen.
+    // `Ok` can never happen; the interpreter loop always exits with an "error"
+    // (but that "error" might be just "regular program termination").
     let Err(err) = res.report_err();
+    // Show diagnostic, if any.
+    let (return_code, leak_check) = report_error(&ecx, err)?;
+
+    // If we get here there was no fatal error.
 
     // 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).
@@ -472,8 +477,7 @@ pub fn eval_entry<'tcx>(
         EnvVars::cleanup(&mut ecx).expect("error during env var cleanup");
     }
 
-    // Process the result.
-    let (return_code, leak_check) = report_error(&ecx, err)?;
+    // Possibly check for memory leaks.
     if leak_check && !ignore_leaks {
         // Check for thread leaks.
         if !ecx.have_all_terminated() {
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 29ed94a2e4a..b4098ca0750 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -602,6 +602,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     // 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
                     // `Variants::Multiple`.
+                    // FIXME: the current logic here is layout-dependent, so enums with
+                    // multiple variants where all but 1 are uninhabited will be recursed into.
+                    // Is that truly what we want?
                     match v.layout.variants {
                         Variants::Multiple { .. } => {
                             // A multi-variant enum, or coroutine, or so.
diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs
index 85fb280a9a9..a3525dcc77a 100644
--- a/src/tools/miri/src/intrinsics/mod.rs
+++ b/src/tools/miri/src/intrinsics/mod.rs
@@ -411,9 +411,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 };
                 let res = this.binary_op(op, &a, &b)?;
                 // `binary_op` already called `generate_nan` if needed.
-                // Apply a relative error of 16ULP to simulate non-deterministic precision loss
+                // Apply a relative error of 4ULP to simulate non-deterministic precision loss
                 // due to optimizations.
-                let res = apply_random_float_error_to_imm(this, res, 4 /* log2(16) */)?;
+                let res = apply_random_float_error_to_imm(this, res, 2 /* log2(4) */)?;
                 this.write_immediate(*res, dest)?;
             }
 
@@ -464,9 +464,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 if !float_finite(&res)? {
                     throw_ub_format!("`{intrinsic_name}` intrinsic produced non-finite value as result");
                 }
-                // Apply a relative error of 16ULP to simulate non-deterministic precision loss
+                // Apply a relative error of 4ULP to simulate non-deterministic precision loss
                 // due to optimizations.
-                let res = apply_random_float_error_to_imm(this, res, 4 /* log2(16) */)?;
+                let res = apply_random_float_error_to_imm(this, res, 2 /* log2(4) */)?;
                 this.write_immediate(*res, dest)?;
             }
 
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 03f76cfa652..5921ba86639 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -121,7 +121,7 @@ pub use crate::borrow_tracker::stacked_borrows::{
 };
 pub use crate::borrow_tracker::tree_borrows::{EvalContextExt as _, Tree};
 pub use crate::borrow_tracker::{BorTag, BorrowTrackerMethod, EvalContextExt as _, RetagFields};
-pub use crate::clock::{Clock, Instant};
+pub use crate::clock::{Instant, MonotonicClock};
 pub use crate::concurrency::cpu_affinity::MAX_CPUS;
 pub use crate::concurrency::data_race::{
     AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, EvalContextExt as _,
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index fb99bdc5176..ea59d327be8 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -486,7 +486,7 @@ pub struct MiriMachine<'tcx> {
     pub(crate) epoll_interests: shims::EpollInterestTable,
 
     /// This machine's monotone clock.
-    pub(crate) clock: Clock,
+    pub(crate) monotonic_clock: MonotonicClock,
 
     /// The set of threads.
     pub(crate) threads: ThreadManager<'tcx>,
@@ -713,7 +713,7 @@ impl<'tcx> MiriMachine<'tcx> {
             preemption_rate: config.preemption_rate,
             report_progress: config.report_progress,
             basic_block_count: 0,
-            clock: Clock::new(config.isolated_op == IsolatedOp::Allow),
+            monotonic_clock: MonotonicClock::new(config.isolated_op == IsolatedOp::Allow),
             #[cfg(unix)]
             native_lib: config.native_lib.as_ref().map(|lib_file_path| {
                 let host_triple = rustc_session::config::host_tuple();
@@ -896,7 +896,7 @@ impl VisitProvenance for MiriMachine<'_> {
             tcx: _,
             isolated_op: _,
             validation: _,
-            clock: _,
+            monotonic_clock: _,
             layouts: _,
             static_roots: _,
             profiler: _,
@@ -1568,7 +1568,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         ecx.maybe_preempt_active_thread();
 
         // Make sure some time passes.
-        ecx.machine.clock.tick();
+        ecx.machine.monotonic_clock.tick();
 
         interp_ok(())
     }
diff --git a/src/tools/miri/src/shims/files.rs b/src/tools/miri/src/shims/files.rs
index 6b4f4cdc922..42603e784bb 100644
--- a/src/tools/miri/src/shims/files.rs
+++ b/src/tools/miri/src/shims/files.rs
@@ -1,6 +1,7 @@
 use std::any::Any;
 use std::collections::BTreeMap;
-use std::io::{IsTerminal, SeekFrom, Write};
+use std::fs::{File, Metadata};
+use std::io::{IsTerminal, Seek, SeekFrom, Write};
 use std::marker::CoercePointee;
 use std::ops::Deref;
 use std::rc::{Rc, Weak};
@@ -192,7 +193,7 @@ pub trait FileDescription: std::fmt::Debug + FileDescriptionExt {
         false
     }
 
-    fn as_unix(&self) -> &dyn UnixFileDescription {
+    fn as_unix<'tcx>(&self, _ecx: &MiriInterpCx<'tcx>) -> &dyn UnixFileDescription {
         panic!("Not a unix file descriptor: {}", self.name());
     }
 }
@@ -278,6 +279,97 @@ impl FileDescription for io::Stderr {
     }
 }
 
+#[derive(Debug)]
+pub struct FileHandle {
+    pub(crate) file: File,
+    pub(crate) writable: bool,
+}
+
+impl FileDescription for FileHandle {
+    fn name(&self) -> &'static str {
+        "file"
+    }
+
+    fn read<'tcx>(
+        self: FileDescriptionRef<Self>,
+        communicate_allowed: bool,
+        ptr: Pointer,
+        len: usize,
+        ecx: &mut MiriInterpCx<'tcx>,
+        finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
+    ) -> InterpResult<'tcx> {
+        assert!(communicate_allowed, "isolation should have prevented even opening a file");
+
+        let result = ecx.read_from_host(&self.file, len, ptr)?;
+        finish.call(ecx, result)
+    }
+
+    fn write<'tcx>(
+        self: FileDescriptionRef<Self>,
+        communicate_allowed: bool,
+        ptr: Pointer,
+        len: usize,
+        ecx: &mut MiriInterpCx<'tcx>,
+        finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
+    ) -> InterpResult<'tcx> {
+        assert!(communicate_allowed, "isolation should have prevented even opening a file");
+
+        let result = ecx.write_to_host(&self.file, len, ptr)?;
+        finish.call(ecx, result)
+    }
+
+    fn seek<'tcx>(
+        &self,
+        communicate_allowed: bool,
+        offset: SeekFrom,
+    ) -> InterpResult<'tcx, io::Result<u64>> {
+        assert!(communicate_allowed, "isolation should have prevented even opening a file");
+        interp_ok((&mut &self.file).seek(offset))
+    }
+
+    fn close<'tcx>(
+        self,
+        communicate_allowed: bool,
+        _ecx: &mut MiriInterpCx<'tcx>,
+    ) -> InterpResult<'tcx, io::Result<()>> {
+        assert!(communicate_allowed, "isolation should have prevented even opening a file");
+        // We sync the file if it was opened in a mode different than read-only.
+        if self.writable {
+            // `File::sync_all` does the checks that are done when closing a file. We do this to
+            // to handle possible errors correctly.
+            let result = self.file.sync_all();
+            // Now we actually close the file and return the result.
+            drop(self.file);
+            interp_ok(result)
+        } else {
+            // We drop the file, this closes it but ignores any errors
+            // produced when closing it. This is done because
+            // `File::sync_all` cannot be done over files like
+            // `/dev/urandom` which are read-only. Check
+            // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439
+            // for a deeper discussion.
+            drop(self.file);
+            interp_ok(Ok(()))
+        }
+    }
+
+    fn metadata<'tcx>(&self) -> InterpResult<'tcx, io::Result<Metadata>> {
+        interp_ok(self.file.metadata())
+    }
+
+    fn is_tty(&self, communicate_allowed: bool) -> bool {
+        communicate_allowed && self.file.is_terminal()
+    }
+
+    fn as_unix<'tcx>(&self, ecx: &MiriInterpCx<'tcx>) -> &dyn UnixFileDescription {
+        assert!(
+            ecx.target_os_is_unix(),
+            "unix file operations are only available for unix targets"
+        );
+        self
+    }
+}
+
 /// Like /dev/null
 #[derive(Debug)]
 pub struct NullOutput;
@@ -300,10 +392,13 @@ impl FileDescription for NullOutput {
     }
 }
 
+/// Internal type of a file-descriptor - this is what [`FdTable`] expects
+pub type FdNum = i32;
+
 /// The file descriptor table
 #[derive(Debug)]
 pub struct FdTable {
-    pub fds: BTreeMap<i32, DynFileDescriptionRef>,
+    pub fds: BTreeMap<FdNum, DynFileDescriptionRef>,
     /// Unique identifier for file description, used to differentiate between various file description.
     next_file_description_id: FdId,
 }
@@ -339,12 +434,12 @@ impl FdTable {
     }
 
     /// Insert a new file description to the FdTable.
-    pub fn insert_new(&mut self, fd: impl FileDescription) -> i32 {
+    pub fn insert_new(&mut self, fd: impl FileDescription) -> FdNum {
         let fd_ref = self.new_ref(fd);
         self.insert(fd_ref)
     }
 
-    pub fn insert(&mut self, fd_ref: DynFileDescriptionRef) -> i32 {
+    pub fn insert(&mut self, fd_ref: DynFileDescriptionRef) -> FdNum {
         self.insert_with_min_num(fd_ref, 0)
     }
 
@@ -352,8 +447,8 @@ impl FdTable {
     pub fn insert_with_min_num(
         &mut self,
         file_handle: DynFileDescriptionRef,
-        min_fd_num: i32,
-    ) -> i32 {
+        min_fd_num: FdNum,
+    ) -> FdNum {
         // Find the lowest unused FD, starting from min_fd. If the first such unused FD is in
         // between used FDs, the find_map combinator will return it. If the first such unused FD
         // is after all other used FDs, the find_map combinator will return None, and we will use
@@ -379,16 +474,16 @@ impl FdTable {
         new_fd_num
     }
 
-    pub fn get(&self, fd_num: i32) -> Option<DynFileDescriptionRef> {
+    pub fn get(&self, fd_num: FdNum) -> Option<DynFileDescriptionRef> {
         let fd = self.fds.get(&fd_num)?;
         Some(fd.clone())
     }
 
-    pub fn remove(&mut self, fd_num: i32) -> Option<DynFileDescriptionRef> {
+    pub fn remove(&mut self, fd_num: FdNum) -> Option<DynFileDescriptionRef> {
         self.fds.remove(&fd_num)
     }
 
-    pub fn is_fd_num(&self, fd_num: i32) -> bool {
+    pub fn is_fd_num(&self, fd_num: FdNum) -> bool {
         self.fds.contains_key(&fd_num)
     }
 }
diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs
index 64b3ce6b4e4..fb80a36af9f 100644
--- a/src/tools/miri/src/shims/time.rs
+++ b/src/tools/miri/src/shims/time.rs
@@ -79,7 +79,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.check_no_isolation("`clock_gettime` with `REALTIME` clocks")?;
             system_time_to_duration(&SystemTime::now())?
         } else if relative_clocks.contains(&clk_id) {
-            this.machine.clock.now().duration_since(this.machine.clock.epoch())
+            this.machine.monotonic_clock.now().duration_since(this.machine.monotonic_clock.epoch())
         } else {
             return this.set_last_error_and_return_i32(LibcError("EINVAL"));
         };
@@ -219,16 +219,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let filetime = this.deref_pointer_as(LPFILETIME_op, this.windows_ty_layout("FILETIME"))?;
 
-        let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC");
-        let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC");
-        let INTERVALS_TO_UNIX_EPOCH = this.eval_windows_u64("time", "INTERVALS_TO_UNIX_EPOCH");
-        let NANOS_PER_INTERVAL = NANOS_PER_SEC / INTERVALS_PER_SEC;
-        let SECONDS_TO_UNIX_EPOCH = INTERVALS_TO_UNIX_EPOCH / INTERVALS_PER_SEC;
-
-        let duration = system_time_to_duration(&SystemTime::now())?
-            + Duration::from_secs(SECONDS_TO_UNIX_EPOCH);
-        let duration_ticks = u64::try_from(duration.as_nanos() / u128::from(NANOS_PER_INTERVAL))
-            .map_err(|_| err_unsup_format!("programs running more than 2^64 Windows ticks after the Windows epoch are not supported"))?;
+        let duration = this.system_time_since_windows_epoch(&SystemTime::now())?;
+        let duration_ticks = this.windows_ticks_for(duration)?;
 
         let dwLowDateTime = u32::try_from(duration_ticks & 0x00000000FFFFFFFF).unwrap();
         let dwHighDateTime = u32::try_from((duration_ticks & 0xFFFFFFFF00000000) >> 32).unwrap();
@@ -248,7 +240,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         // QueryPerformanceCounter uses a hardware counter as its basis.
         // Miri will emulate a counter with a resolution of 1 nanosecond.
-        let duration = this.machine.clock.now().duration_since(this.machine.clock.epoch());
+        let duration =
+            this.machine.monotonic_clock.now().duration_since(this.machine.monotonic_clock.epoch());
         let qpc = i64::try_from(duration.as_nanos()).map_err(|_| {
             err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported")
         })?;
@@ -280,6 +273,30 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         interp_ok(Scalar::from_i32(-1)) // Return non-zero on success
     }
 
+    #[allow(non_snake_case, clippy::arithmetic_side_effects)]
+    fn system_time_since_windows_epoch(&self, time: &SystemTime) -> InterpResult<'tcx, Duration> {
+        let this = self.eval_context_ref();
+
+        let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC");
+        let INTERVALS_TO_UNIX_EPOCH = this.eval_windows_u64("time", "INTERVALS_TO_UNIX_EPOCH");
+        let SECONDS_TO_UNIX_EPOCH = INTERVALS_TO_UNIX_EPOCH / INTERVALS_PER_SEC;
+
+        interp_ok(system_time_to_duration(time)? + Duration::from_secs(SECONDS_TO_UNIX_EPOCH))
+    }
+
+    #[allow(non_snake_case, clippy::arithmetic_side_effects)]
+    fn windows_ticks_for(&self, duration: Duration) -> InterpResult<'tcx, u64> {
+        let this = self.eval_context_ref();
+
+        let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC");
+        let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC");
+        let NANOS_PER_INTERVAL = NANOS_PER_SEC / INTERVALS_PER_SEC;
+
+        let ticks = u64::try_from(duration.as_nanos() / u128::from(NANOS_PER_INTERVAL))
+            .map_err(|_| err_unsup_format!("programs running more than 2^64 Windows ticks after the Windows epoch are not supported"))?;
+        interp_ok(ticks)
+    }
+
     fn mach_absolute_time(&self) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_ref();
 
@@ -287,7 +304,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         // This returns a u64, with time units determined dynamically by `mach_timebase_info`.
         // We return plain nanoseconds.
-        let duration = this.machine.clock.now().duration_since(this.machine.clock.epoch());
+        let duration =
+            this.machine.monotonic_clock.now().duration_since(this.machine.monotonic_clock.epoch());
         let res = u64::try_from(duration.as_nanos()).map_err(|_| {
             err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported")
         })?;
diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs
index 3f85b9ae9bd..41be9df7e2d 100644
--- a/src/tools/miri/src/shims/unix/fd.rs
+++ b/src/tools/miri/src/shims/unix/fd.rs
@@ -121,7 +121,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             throw_unsup_format!("unsupported flags {:#x}", op);
         };
 
-        let result = fd.as_unix().flock(this.machine.communicate(), parsed_op)?;
+        let result = fd.as_unix(this).flock(this.machine.communicate(), parsed_op)?;
         // return `0` if flock is successful
         let result = result.map(|()| 0i32);
         interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
@@ -273,7 +273,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let Ok(offset) = u64::try_from(offset) else {
                     return this.set_last_error_and_return(LibcError("EINVAL"), dest);
                 };
-                fd.as_unix().pread(communicate, offset, buf, count, this, finish)?
+                fd.as_unix(this).pread(communicate, offset, buf, count, this, finish)?
             }
         };
         interp_ok(())
@@ -333,7 +333,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let Ok(offset) = u64::try_from(offset) else {
                     return this.set_last_error_and_return(LibcError("EINVAL"), dest);
                 };
-                fd.as_unix().pwrite(communicate, buf, count, offset, this, finish)?
+                fd.as_unix(this).pwrite(communicate, buf, count, offset, this, finish)?
             }
         };
         interp_ok(())
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index 1770b99c0a2..5e6259c3574 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -231,6 +231,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(result, dest)?;
             }
             "flock" => {
+                // Currently this function does not exist on all Unixes, e.g. on Solaris.
+                this.check_target_os(&["linux", "freebsd", "macos", "illumos"], link_name)?;
                 let [fd, op] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let op = this.read_scalar(op)?.to_i32()?;
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 08d06fe5d4c..21a386b2927 100644
--- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
@@ -2,6 +2,7 @@ use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
 use rustc_target::callconv::{Conv, FnAbi};
 
+use super::sync::EvalContextExt as _;
 use crate::shims::unix::*;
 use crate::*;
 
@@ -55,6 +56,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(res, dest)?;
             }
 
+            // Synchronization primitives
+            "_umtx_op" => {
+                let [obj, op, val, uaddr, uaddr2] =
+                    this.check_shim(abi, Conv::C, link_name, args)?;
+                this._umtx_op(obj, op, val, uaddr, uaddr2, dest)?;
+            }
+
             // File related shims
             // For those, we both intercept `func` and `call@FBSD_1.0` symbols cases
             // since freebsd 12 the former form can be expected.
diff --git a/src/tools/miri/src/shims/unix/freebsd/mod.rs b/src/tools/miri/src/shims/unix/freebsd/mod.rs
index 09c6507b24f..50fb2b9d328 100644
--- a/src/tools/miri/src/shims/unix/freebsd/mod.rs
+++ b/src/tools/miri/src/shims/unix/freebsd/mod.rs
@@ -1 +1,2 @@
 pub mod foreign_items;
+pub mod sync;
diff --git a/src/tools/miri/src/shims/unix/freebsd/sync.rs b/src/tools/miri/src/shims/unix/freebsd/sync.rs
new file mode 100644
index 00000000000..54650f35b2c
--- /dev/null
+++ b/src/tools/miri/src/shims/unix/freebsd/sync.rs
@@ -0,0 +1,251 @@
+//! Contains FreeBSD-specific synchronization functions
+
+use core::time::Duration;
+
+use crate::concurrency::sync::FutexRef;
+use crate::*;
+
+pub struct FreeBsdFutex {
+    futex: FutexRef,
+}
+
+/// Extended variant of the `timespec` struct.
+pub struct UmtxTime {
+    timeout: Duration,
+    abs_time: bool,
+    timeout_clock: TimeoutClock,
+}
+
+impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
+pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
+    /// Implementation of the FreeBSD [`_umtx_op`](https://man.freebsd.org/cgi/man.cgi?query=_umtx_op&sektion=2&manpath=FreeBSD+14.2-RELEASE+and+Ports) syscall.
+    /// This is used for futex operations on FreeBSD.
+    ///
+    /// `obj`: a pointer to the futex object (can be a lot of things, mostly *AtomicU32)
+    /// `op`: the futex operation to run
+    /// `val`: the current value of the object as a `c_long` (for wait/wake)
+    /// `uaddr`: `op`-specific optional parameter, pointer-sized integer or pointer to an `op`-specific struct
+    /// `uaddr2`: `op`-specific optional parameter, pointer-sized integer or pointer to an `op`-specific struct
+    /// `dest`: the place this syscall returns to, 0 for success, -1 for failure
+    ///
+    /// # Note
+    /// Curently only the WAIT and WAKE operations are implemented.
+    fn _umtx_op(
+        &mut self,
+        obj: &OpTy<'tcx>,
+        op: &OpTy<'tcx>,
+        val: &OpTy<'tcx>,
+        uaddr: &OpTy<'tcx>,
+        uaddr2: &OpTy<'tcx>,
+        dest: &MPlaceTy<'tcx>,
+    ) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+
+        let obj = this.read_pointer(obj)?;
+        let op = this.read_scalar(op)?.to_i32()?;
+        let val = this.read_target_usize(val)?;
+        let uaddr = this.read_target_usize(uaddr)?;
+        let uaddr2 = this.read_pointer(uaddr2)?;
+
+        let wait = this.eval_libc_i32("UMTX_OP_WAIT");
+        let wait_uint = this.eval_libc_i32("UMTX_OP_WAIT_UINT");
+        let wait_uint_private = this.eval_libc_i32("UMTX_OP_WAIT_UINT_PRIVATE");
+
+        let wake = this.eval_libc_i32("UMTX_OP_WAKE");
+        let wake_private = this.eval_libc_i32("UMTX_OP_WAKE_PRIVATE");
+
+        let timespec_layout = this.libc_ty_layout("timespec");
+        let umtx_time_layout = this.libc_ty_layout("_umtx_time");
+        assert!(
+            timespec_layout.size != umtx_time_layout.size,
+            "`struct timespec` and `struct _umtx_time` should have different sizes."
+        );
+
+        match op {
+            // UMTX_OP_WAIT_UINT and UMTX_OP_WAIT_UINT_PRIVATE only differ in whether they work across
+            // processes or not. For Miri, we can treat them the same.
+            op if op == wait || op == wait_uint || op == wait_uint_private => {
+                let obj_layout =
+                    if op == wait { this.machine.layouts.isize } else { this.machine.layouts.u32 };
+                let obj = this.ptr_to_mplace(obj, obj_layout);
+
+                // Read the Linux futex wait implementation in Miri to understand why this fence is needed.
+                this.atomic_fence(AtomicFenceOrd::SeqCst)?;
+                let obj_val = this
+                    .read_scalar_atomic(&obj, AtomicReadOrd::Acquire)?
+                    .to_bits(obj_layout.size)?; // isize and u32 can have different sizes
+
+                if obj_val == u128::from(val) {
+                    // This cannot fail since we already did an atomic acquire read on that pointer.
+                    // Acquire reads are only allowed on mutable memory.
+                    let futex_ref = this
+                        .get_sync_or_init(obj.ptr(), |_| FreeBsdFutex { futex: Default::default() })
+                        .unwrap()
+                        .futex
+                        .clone();
+
+                    // From the manual:
+                    // The timeout is specified by passing either the address of `struct timespec`, or its
+                    // extended variant, `struct _umtx_time`, as the `uaddr2` argument of _umtx_op().
+                    // They are distinguished by the `uaddr` value, which must be equal
+                    // to the size of the structure pointed to by `uaddr2`, casted to uintptr_t.
+                    let timeout = if this.ptr_is_null(uaddr2)? {
+                        // no timeout parameter
+                        None
+                    } else {
+                        if uaddr == umtx_time_layout.size.bytes() {
+                            // `uaddr2` points to a `struct _umtx_time`.
+                            let umtx_time_place = this.ptr_to_mplace(uaddr2, umtx_time_layout);
+
+                            let umtx_time = match this.read_umtx_time(&umtx_time_place)? {
+                                Some(ut) => ut,
+                                None => {
+                                    return this
+                                        .set_last_error_and_return(LibcError("EINVAL"), dest);
+                                }
+                            };
+
+                            let anchor = if umtx_time.abs_time {
+                                TimeoutAnchor::Absolute
+                            } else {
+                                TimeoutAnchor::Relative
+                            };
+
+                            Some((umtx_time.timeout_clock, anchor, umtx_time.timeout))
+                        } else if uaddr == timespec_layout.size.bytes() {
+                            // RealTime clock can't be used in isolation mode.
+                            this.check_no_isolation("`_umtx_op` with `timespec` timeout")?;
+
+                            // `uaddr2` points to a `struct timespec`.
+                            let timespec = this.ptr_to_mplace(uaddr2, timespec_layout);
+                            let duration = match this.read_timespec(&timespec)? {
+                                Some(duration) => duration,
+                                None => {
+                                    return this
+                                        .set_last_error_and_return(LibcError("EINVAL"), dest);
+                                }
+                            };
+
+                            // FreeBSD does not seem to document which clock is used when the timeout
+                            // is passed as a `struct timespec*`. Based on discussions online and the source
+                            // code (umtx_copyin_umtx_time() in kern_umtx.c), it seems to default to CLOCK_REALTIME,
+                            // so that's what we also do.
+                            // Discussion in golang: https://github.com/golang/go/issues/17168#issuecomment-250235271
+                            Some((TimeoutClock::RealTime, TimeoutAnchor::Relative, duration))
+                        } else {
+                            return this.set_last_error_and_return(LibcError("EINVAL"), dest);
+                        }
+                    };
+
+                    let dest = dest.clone();
+                    this.futex_wait(
+                        futex_ref,
+                        u32::MAX, // we set the bitset to include all bits
+                        timeout,
+                        callback!(
+                            @capture<'tcx> {
+                                dest: MPlaceTy<'tcx>,
+                            }
+                            |ecx, unblock: UnblockKind| match unblock {
+                                UnblockKind::Ready => {
+                                    // From the manual:
+                                    // If successful, all requests, except UMTX_SHM_CREAT and UMTX_SHM_LOOKUP
+                                    // sub-requests of the UMTX_OP_SHM request, will return zero.
+                                    ecx.write_int(0, &dest)
+                                }
+                                UnblockKind::TimedOut => {
+                                    ecx.set_last_error_and_return(LibcError("ETIMEDOUT"), &dest)
+                                }
+                            }
+                        ),
+                    );
+                    interp_ok(())
+                } else {
+                    // The manual doesn’t specify what should happen if the futex value doesn’t match the expected one.
+                    // On FreeBSD 14.2, testing shows that WAIT operations return 0 even when the value is incorrect.
+                    this.write_int(0, dest)?;
+                    interp_ok(())
+                }
+            }
+            // UMTX_OP_WAKE and UMTX_OP_WAKE_PRIVATE only differ in whether they work across
+            // processes or not. For Miri, we can treat them the same.
+            op if op == wake || op == wake_private => {
+                let Some(futex_ref) =
+                    this.get_sync_or_init(obj, |_| FreeBsdFutex { futex: Default::default() })
+                else {
+                    // From Linux implemenation:
+                    // No AllocId, or no live allocation at that AllocId.
+                    // Return an error code. (That seems nicer than silently doing something non-intuitive.)
+                    // This means that if an address gets reused by a new allocation,
+                    // we'll use an independent futex queue for this... that seems acceptable.
+                    return this.set_last_error_and_return(LibcError("EFAULT"), dest);
+                };
+                let futex_ref = futex_ref.futex.clone();
+
+                // Saturating cast for when usize is smaller than u64.
+                let count = usize::try_from(val).unwrap_or(usize::MAX);
+
+                // Read the Linux futex wake implementation in Miri to understand why this fence is needed.
+                this.atomic_fence(AtomicFenceOrd::SeqCst)?;
+
+                // `_umtx_op` doesn't return the amount of woken threads.
+                let _woken = this.futex_wake(
+                    &futex_ref,
+                    u32::MAX, // we set the bitset to include all bits
+                    count,
+                )?;
+
+                // From the manual:
+                // If successful, all requests, except UMTX_SHM_CREAT and UMTX_SHM_LOOKUP
+                // sub-requests of the UMTX_OP_SHM request, will return zero.
+                this.write_int(0, dest)?;
+                interp_ok(())
+            }
+            op => {
+                throw_unsup_format!("Miri does not support `_umtx_op` syscall with op={}", op)
+            }
+        }
+    }
+
+    /// Parses a `_umtx_time` struct.
+    /// Returns `None` if the underlying `timespec` struct is invalid.
+    fn read_umtx_time(&mut self, ut: &MPlaceTy<'tcx>) -> InterpResult<'tcx, Option<UmtxTime>> {
+        let this = self.eval_context_mut();
+        // Only flag allowed is UMTX_ABSTIME.
+        let abs_time = this.eval_libc_u32("UMTX_ABSTIME");
+
+        let timespec_place = this.project_field(ut, 0)?;
+        // Inner `timespec` must still be valid.
+        let duration = match this.read_timespec(&timespec_place)? {
+            Some(dur) => dur,
+            None => return interp_ok(None),
+        };
+
+        let flags_place = this.project_field(ut, 1)?;
+        let flags = this.read_scalar(&flags_place)?.to_u32()?;
+        let abs_time_flag = flags == abs_time;
+
+        let clock_id_place = this.project_field(ut, 2)?;
+        let clock_id = this.read_scalar(&clock_id_place)?.to_i32()?;
+        let timeout_clock = this.translate_umtx_time_clock_id(clock_id)?;
+
+        interp_ok(Some(UmtxTime { timeout: duration, abs_time: abs_time_flag, timeout_clock }))
+    }
+
+    /// Translate raw FreeBSD clockid to a Miri TimeoutClock.
+    /// FIXME: share this code with the pthread and clock_gettime shims.
+    fn translate_umtx_time_clock_id(&mut self, raw_id: i32) -> InterpResult<'tcx, TimeoutClock> {
+        let this = self.eval_context_mut();
+
+        let timeout = if raw_id == this.eval_libc_i32("CLOCK_REALTIME") {
+            // RealTime clock can't be used in isolation mode.
+            this.check_no_isolation("`_umtx_op` with `CLOCK_REALTIME` timeout")?;
+            TimeoutClock::RealTime
+        } else if raw_id == this.eval_libc_i32("CLOCK_MONOTONIC") {
+            TimeoutClock::Monotonic
+        } else {
+            throw_unsup_format!("unsupported clock id {raw_id}");
+        };
+        interp_ok(timeout)
+    }
+}
diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs
index f8e0c638c90..fc0f57694a7 100644
--- a/src/tools/miri/src/shims/unix/fs.rs
+++ b/src/tools/miri/src/shims/unix/fs.rs
@@ -2,10 +2,9 @@
 
 use std::borrow::Cow;
 use std::fs::{
-    DirBuilder, File, FileType, Metadata, OpenOptions, ReadDir, read_dir, remove_dir, remove_file,
-    rename,
+    DirBuilder, File, FileType, OpenOptions, ReadDir, read_dir, remove_dir, remove_file, rename,
 };
-use std::io::{self, ErrorKind, IsTerminal, Read, Seek, SeekFrom, Write};
+use std::io::{self, ErrorKind, Read, Seek, SeekFrom, Write};
 use std::path::{Path, PathBuf};
 use std::time::SystemTime;
 
@@ -14,98 +13,11 @@ use rustc_data_structures::fx::FxHashMap;
 
 use self::shims::time::system_time_to_duration;
 use crate::helpers::check_min_vararg_count;
-use crate::shims::files::{EvalContextExt as _, FileDescription, FileDescriptionRef};
+use crate::shims::files::FileHandle;
 use crate::shims::os_str::bytes_to_os_str;
 use crate::shims::unix::fd::{FlockOp, UnixFileDescription};
 use crate::*;
 
-#[derive(Debug)]
-struct FileHandle {
-    file: File,
-    writable: bool,
-}
-
-impl FileDescription for FileHandle {
-    fn name(&self) -> &'static str {
-        "file"
-    }
-
-    fn read<'tcx>(
-        self: FileDescriptionRef<Self>,
-        communicate_allowed: bool,
-        ptr: Pointer,
-        len: usize,
-        ecx: &mut MiriInterpCx<'tcx>,
-        finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
-    ) -> InterpResult<'tcx> {
-        assert!(communicate_allowed, "isolation should have prevented even opening a file");
-
-        let result = ecx.read_from_host(&self.file, len, ptr)?;
-        finish.call(ecx, result)
-    }
-
-    fn write<'tcx>(
-        self: FileDescriptionRef<Self>,
-        communicate_allowed: bool,
-        ptr: Pointer,
-        len: usize,
-        ecx: &mut MiriInterpCx<'tcx>,
-        finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
-    ) -> InterpResult<'tcx> {
-        assert!(communicate_allowed, "isolation should have prevented even opening a file");
-
-        let result = ecx.write_to_host(&self.file, len, ptr)?;
-        finish.call(ecx, result)
-    }
-
-    fn seek<'tcx>(
-        &self,
-        communicate_allowed: bool,
-        offset: SeekFrom,
-    ) -> InterpResult<'tcx, io::Result<u64>> {
-        assert!(communicate_allowed, "isolation should have prevented even opening a file");
-        interp_ok((&mut &self.file).seek(offset))
-    }
-
-    fn close<'tcx>(
-        self,
-        communicate_allowed: bool,
-        _ecx: &mut MiriInterpCx<'tcx>,
-    ) -> InterpResult<'tcx, io::Result<()>> {
-        assert!(communicate_allowed, "isolation should have prevented even opening a file");
-        // We sync the file if it was opened in a mode different than read-only.
-        if self.writable {
-            // `File::sync_all` does the checks that are done when closing a file. We do this to
-            // to handle possible errors correctly.
-            let result = self.file.sync_all();
-            // Now we actually close the file and return the result.
-            drop(self.file);
-            interp_ok(result)
-        } else {
-            // We drop the file, this closes it but ignores any errors
-            // produced when closing it. This is done because
-            // `File::sync_all` cannot be done over files like
-            // `/dev/urandom` which are read-only. Check
-            // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439
-            // for a deeper discussion.
-            drop(self.file);
-            interp_ok(Ok(()))
-        }
-    }
-
-    fn metadata<'tcx>(&self) -> InterpResult<'tcx, io::Result<Metadata>> {
-        interp_ok(self.file.metadata())
-    }
-
-    fn is_tty(&self, communicate_allowed: bool) -> bool {
-        communicate_allowed && self.file.is_terminal()
-    }
-
-    fn as_unix(&self) -> &dyn UnixFileDescription {
-        self
-    }
-}
-
 impl UnixFileDescription for FileHandle {
     fn pread<'tcx>(
         &self,
diff --git a/src/tools/miri/src/shims/unix/linux_like/epoll.rs b/src/tools/miri/src/shims/unix/linux_like/epoll.rs
index de8bcb54aef..b489595b4cd 100644
--- a/src/tools/miri/src/shims/unix/linux_like/epoll.rs
+++ b/src/tools/miri/src/shims/unix/linux_like/epoll.rs
@@ -153,7 +153,7 @@ impl FileDescription for Epoll {
         interp_ok(Ok(()))
     }
 
-    fn as_unix(&self) -> &dyn UnixFileDescription {
+    fn as_unix<'tcx>(&self, _ecx: &MiriInterpCx<'tcx>) -> &dyn UnixFileDescription {
         self
     }
 }
@@ -590,7 +590,7 @@ fn check_and_update_one_event_interest<'tcx>(
     ecx: &MiriInterpCx<'tcx>,
 ) -> InterpResult<'tcx, bool> {
     // Get the bitmask of ready events for a file description.
-    let ready_events_bitmask = fd_ref.as_unix().get_epoll_ready_events()?.get_event_bitmask(ecx);
+    let ready_events_bitmask = fd_ref.as_unix(ecx).get_epoll_ready_events()?.get_event_bitmask(ecx);
     let epoll_event_interest = interest.borrow();
     let epfd = epoll_event_interest.weak_epfd.upgrade().unwrap();
     // This checks if any of the events specified in epoll_event_interest.events
diff --git a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs
index 936d436bd82..ee7deb8d383 100644
--- a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs
+++ b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs
@@ -100,7 +100,7 @@ impl FileDescription for EventFd {
         eventfd_write(buf_place, self, ecx, finish)
     }
 
-    fn as_unix(&self) -> &dyn UnixFileDescription {
+    fn as_unix<'tcx>(&self, _ecx: &MiriInterpCx<'tcx>) -> &dyn UnixFileDescription {
         self
     }
 }
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 918fd8dd52d..5046e965082 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -222,7 +222,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(res, dest)?;
             }
 
-            // Futex primitives
+            // Synchronization primitives
             "os_sync_wait_on_address" => {
                 let [addr_op, value_op, size_op, flags_op] =
                     this.check_shim(abi, Conv::C, link_name, args)?;
@@ -273,7 +273,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     addr_op, size_op, flags_op, /* all */ true, dest,
                 )?;
             }
-
             "os_unfair_lock_lock" => {
                 let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.os_unfair_lock_lock(lock_op)?;
diff --git a/src/tools/miri/src/shims/unix/unnamed_socket.rs b/src/tools/miri/src/shims/unix/unnamed_socket.rs
index e183bfdf0e1..135d8f6bee7 100644
--- a/src/tools/miri/src/shims/unix/unnamed_socket.rs
+++ b/src/tools/miri/src/shims/unix/unnamed_socket.rs
@@ -107,7 +107,7 @@ impl FileDescription for AnonSocket {
         anonsocket_write(self, ptr, len, ecx, finish)
     }
 
-    fn as_unix(&self) -> &dyn UnixFileDescription {
+    fn as_unix<'tcx>(&self, _ecx: &MiriInterpCx<'tcx>) -> &dyn UnixFileDescription {
         self
     }
 }
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index fae6170a9e7..8dcadbed130 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -9,14 +9,9 @@ use rustc_target::callconv::{Conv, FnAbi};
 
 use self::shims::windows::handle::{Handle, PseudoHandle};
 use crate::shims::os_str::bytes_to_os_str;
-use crate::shims::windows::handle::HandleError;
 use crate::shims::windows::*;
 use crate::*;
 
-// The NTSTATUS STATUS_INVALID_HANDLE (0xC0000008) encoded as a HRESULT by setting the N bit.
-// (https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/0642cb2f-2075-4469-918c-4441e69c548a)
-const STATUS_INVALID_HANDLE: u32 = 0xD0000008;
-
 pub fn is_dyn_sym(name: &str) -> bool {
     // std does dynamic detection for these symbols
     matches!(
@@ -26,57 +21,107 @@ pub fn is_dyn_sym(name: &str) -> bool {
 }
 
 #[cfg(windows)]
-fn win_absolute<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result<PathBuf>> {
+fn win_get_full_path_name<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result<PathBuf>> {
     // We are on Windows so we can simply let the host do this.
     interp_ok(path::absolute(path))
 }
 
 #[cfg(unix)]
 #[expect(clippy::get_first, clippy::arithmetic_side_effects)]
-fn win_absolute<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result<PathBuf>> {
-    // We are on Unix, so we need to implement parts of the logic ourselves.
+fn win_get_full_path_name<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result<PathBuf>> {
+    use std::sync::LazyLock;
+
+    use rustc_data_structures::fx::FxHashSet;
+
+    // We are on Unix, so we need to implement parts of the logic ourselves. `path` will use `/`
+    // separators, and the result should also use `/`.
+    // See <https://chrisdenton.github.io/omnipath/Overview.html#absolute-win32-paths> for more
+    // information about Windows paths.
+    // This does not handle all corner cases correctly, see
+    // <https://github.com/rust-lang/miri/pull/4262#issuecomment-2792168853> for more cursed
+    // examples.
     let bytes = path.as_os_str().as_encoded_bytes();
-    // If it starts with `//` (these were backslashes but are already converted)
-    // then this is a magic special path, we just leave it unchanged.
-    if bytes.get(0).copied() == Some(b'/') && bytes.get(1).copied() == Some(b'/') {
+    // If it starts with `//./` or `//?/` then this is a magic special path, we just leave it
+    // unchanged.
+    if bytes.get(0).copied() == Some(b'/')
+        && bytes.get(1).copied() == Some(b'/')
+        && matches!(bytes.get(2), Some(b'.' | b'?'))
+        && bytes.get(3).copied() == Some(b'/')
+    {
         return interp_ok(Ok(path.into()));
     };
-    // Special treatment for Windows' magic filenames: they are treated as being relative to `\\.\`.
-    let magic_filenames = &[
-        "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8",
-        "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
-    ];
-    if magic_filenames.iter().any(|m| m.as_bytes() == bytes) {
-        let mut result: Vec<u8> = br"//./".into();
+    let is_unc = bytes.starts_with(b"//");
+    // Special treatment for Windows' magic filenames: they are treated as being relative to `//./`.
+    static MAGIC_FILENAMES: LazyLock<FxHashSet<&'static str>> = LazyLock::new(|| {
+        FxHashSet::from_iter([
+            "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7",
+            "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
+        ])
+    });
+    if str::from_utf8(bytes).is_ok_and(|s| MAGIC_FILENAMES.contains(&*s.to_ascii_uppercase())) {
+        let mut result: Vec<u8> = b"//./".into();
         result.extend(bytes);
         return interp_ok(Ok(bytes_to_os_str(&result)?.into()));
     }
     // Otherwise we try to do something kind of close to what Windows does, but this is probably not
-    // right in all cases. We iterate over the components between `/`, and remove trailing `.`,
-    // except that trailing `..` remain unchanged.
-    let mut result = vec![];
+    // right in all cases.
+    let mut result: Vec<&[u8]> = vec![]; // will be a vector of components, joined by `/`.
     let mut bytes = bytes; // the remaining bytes to process
-    loop {
-        let len = bytes.iter().position(|&b| b == b'/').unwrap_or(bytes.len());
-        let mut component = &bytes[..len];
-        if len >= 2 && component[len - 1] == b'.' && component[len - 2] != b'.' {
-            // Strip trailing `.`
-            component = &component[..len - 1];
+    let mut stop = false;
+    while !stop {
+        // Find next component, and advance `bytes`.
+        let mut component = match bytes.iter().position(|&b| b == b'/') {
+            Some(pos) => {
+                let (component, tail) = bytes.split_at(pos);
+                bytes = &tail[1..]; // remove the `/`.
+                component
+            }
+            None => {
+                // There's no more `/`.
+                stop = true;
+                let component = bytes;
+                bytes = &[];
+                component
+            }
+        };
+        // `NUL` and only `NUL` also gets changed to be relative to `//./` later in the path.
+        // (This changed with Windows 11; previously, all magic filenames behaved like this.)
+        // Also, this does not apply to UNC paths.
+        if !is_unc && component.eq_ignore_ascii_case(b"NUL") {
+            let mut result: Vec<u8> = b"//./".into();
+            result.extend(component);
+            return interp_ok(Ok(bytes_to_os_str(&result)?.into()));
         }
-        // Add this component to output.
-        result.extend(component);
-        // Prepare next iteration.
-        if len < bytes.len() {
-            // There's a component after this; add `/` and process remaining bytes.
-            result.push(b'/');
-            bytes = &bytes[len + 1..];
+        // Deal with `..` -- Windows handles this entirely syntactically.
+        if component == b".." {
+            // Remove previous component, unless we are at the "root" already, then just ignore the `..`.
+            let is_root = {
+                // Paths like `/C:`.
+                result.len() == 2 && matches!(result[0], []) && matches!(result[1], [_, b':'])
+            } || {
+                // Paths like `//server/share`
+                result.len() == 4 && matches!(result[0], []) && matches!(result[1], [])
+            };
+            if !is_root {
+                result.pop();
+            }
             continue;
-        } else {
-            // This was the last component and it did not have a trailing `/`.
-            break;
         }
+        // Preserve this component.
+        // Strip trailing `.`, but preserve trailing `..`. But not for UNC paths!
+        let len = component.len();
+        if !is_unc && len >= 2 && component[len - 1] == b'.' && component[len - 2] != b'.' {
+            component = &component[..len - 1];
+        }
+        // Add this component to output.
+        result.push(component);
+    }
+    // Drive letters must be followed by a `/`.
+    if result.len() == 2 && matches!(result[0], []) && matches!(result[1], [_, b':']) {
+        result.push(&[]);
     }
-    // Let the host `absolute` function do working-dir handling
+    // Let the host `absolute` function do working-dir handling.
+    let result = result.join(&b'/');
     interp_ok(path::absolute(bytes_to_os_str(&result)?))
 }
 
@@ -231,7 +276,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 }
 
                 let filename = this.read_path_from_wide_str(filename)?;
-                let result = match win_absolute(&filename)? {
+                let result = match win_get_full_path_name(&filename)? {
                     Err(err) => {
                         this.set_last_error(err)?;
                         Scalar::from_u32(0) // return zero upon failure
@@ -246,6 +291,32 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 };
                 this.write_scalar(result, dest)?;
             }
+            "CreateFileW" => {
+                let [
+                    file_name,
+                    desired_access,
+                    share_mode,
+                    security_attributes,
+                    creation_disposition,
+                    flags_and_attributes,
+                    template_file,
+                ] = this.check_shim(abi, sys_conv, link_name, args)?;
+                let handle = this.CreateFileW(
+                    file_name,
+                    desired_access,
+                    share_mode,
+                    security_attributes,
+                    creation_disposition,
+                    flags_and_attributes,
+                    template_file,
+                )?;
+                this.write_scalar(handle.to_scalar(this), dest)?;
+            }
+            "GetFileInformationByHandle" => {
+                let [handle, info] = this.check_shim(abi, sys_conv, link_name, args)?;
+                let res = this.GetFileInformationByHandle(handle, info)?;
+                this.write_scalar(res, dest)?;
+            }
 
             // Allocation
             "HeapAlloc" => {
@@ -325,6 +396,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let last_error = this.get_last_error()?;
                 this.write_scalar(last_error, dest)?;
             }
+            "RtlNtStatusToDosError" => {
+                let [status] = this.check_shim(abi, sys_conv, link_name, args)?;
+                let status = this.read_scalar(status)?.to_u32()?;
+                let err = match status {
+                    // STATUS_MEDIA_WRITE_PROTECTED => ERROR_WRITE_PROTECT
+                    0xC00000A2 => 19,
+                    // STATUS_FILE_INVALID => ERROR_FILE_INVALID
+                    0xC0000098 => 1006,
+                    // STATUS_DISK_FULL => ERROR_DISK_FULL
+                    0xC000007F => 112,
+                    // STATUS_IO_DEVICE_ERROR => ERROR_IO_DEVICE
+                    0xC0000185 => 1117,
+                    // STATUS_ACCESS_DENIED => ERROR_ACCESS_DENIED
+                    0xC0000022 => 5,
+                    // Anything without an error code => ERROR_MR_MID_NOT_FOUND
+                    _ => 317,
+                };
+                this.write_scalar(Scalar::from_i32(err), dest)?;
+            }
 
             // Querying system information
             "GetSystemInfo" => {
@@ -498,52 +588,37 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "SetThreadDescription" => {
                 let [handle, name] = this.check_shim(abi, sys_conv, link_name, args)?;
 
-                let handle = this.read_scalar(handle)?;
+                let handle = this.read_handle(handle, "SetThreadDescription")?;
                 let name = this.read_wide_str(this.read_pointer(name)?)?;
 
-                let thread = match Handle::try_from_scalar(handle, this)? {
-                    Ok(Handle::Thread(thread)) => Ok(thread),
-                    Ok(Handle::Pseudo(PseudoHandle::CurrentThread)) => Ok(this.active_thread()),
-                    Ok(_) | Err(HandleError::InvalidHandle) =>
-                        this.invalid_handle("SetThreadDescription")?,
-                    Err(HandleError::ThreadNotFound(e)) => Err(e),
-                };
-                let res = match thread {
-                    Ok(thread) => {
-                        // FIXME: use non-lossy conversion
-                        this.set_thread_name(thread, String::from_utf16_lossy(&name).into_bytes());
-                        Scalar::from_u32(0)
-                    }
-                    Err(_) => Scalar::from_u32(STATUS_INVALID_HANDLE),
+                let thread = match handle {
+                    Handle::Thread(thread) => thread,
+                    Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
+                    _ => this.invalid_handle("SetThreadDescription")?,
                 };
-
-                this.write_scalar(res, dest)?;
+                // FIXME: use non-lossy conversion
+                this.set_thread_name(thread, String::from_utf16_lossy(&name).into_bytes());
+                this.write_scalar(Scalar::from_u32(0), dest)?;
             }
             "GetThreadDescription" => {
                 let [handle, name_ptr] = this.check_shim(abi, sys_conv, link_name, args)?;
 
-                let handle = this.read_scalar(handle)?;
+                let handle = this.read_handle(handle, "GetThreadDescription")?;
                 let name_ptr = this.deref_pointer_as(name_ptr, this.machine.layouts.mut_raw_ptr)?; // the pointer where we should store the ptr to the name
 
-                let thread = match Handle::try_from_scalar(handle, this)? {
-                    Ok(Handle::Thread(thread)) => Ok(thread),
-                    Ok(Handle::Pseudo(PseudoHandle::CurrentThread)) => Ok(this.active_thread()),
-                    Ok(_) | Err(HandleError::InvalidHandle) =>
-                        this.invalid_handle("GetThreadDescription")?,
-                    Err(HandleError::ThreadNotFound(e)) => Err(e),
-                };
-                let (name, res) = match thread {
-                    Ok(thread) => {
-                        // Looks like the default thread name is empty.
-                        let name = this.get_thread_name(thread).unwrap_or(b"").to_owned();
-                        let name = this.alloc_os_str_as_wide_str(
-                            bytes_to_os_str(&name)?,
-                            MiriMemoryKind::WinLocal.into(),
-                        )?;
-                        (Scalar::from_maybe_pointer(name, this), Scalar::from_u32(0))
-                    }
-                    Err(_) => (Scalar::null_ptr(this), Scalar::from_u32(STATUS_INVALID_HANDLE)),
+                let thread = match handle {
+                    Handle::Thread(thread) => thread,
+                    Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
+                    _ => this.invalid_handle("GetThreadDescription")?,
                 };
+                // Looks like the default thread name is empty.
+                let name = this.get_thread_name(thread).unwrap_or(b"").to_owned();
+                let name = this.alloc_os_str_as_wide_str(
+                    bytes_to_os_str(&name)?,
+                    MiriMemoryKind::WinLocal.into(),
+                )?;
+                let name = Scalar::from_maybe_pointer(name, this);
+                let res = Scalar::from_u32(0);
 
                 this.write_scalar(name, &name_ptr)?;
                 this.write_scalar(res, dest)?;
@@ -638,11 +713,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let [handle, filename, size] = this.check_shim(abi, sys_conv, link_name, args)?;
                 this.check_no_isolation("`GetModuleFileNameW`")?;
 
-                let handle = this.read_target_usize(handle)?;
+                let handle = this.read_handle(handle, "GetModuleFileNameW")?;
                 let filename = this.read_pointer(filename)?;
                 let size = this.read_scalar(size)?.to_u32()?;
 
-                if handle != 0 {
+                if handle != Handle::Null {
                     throw_unsup_format!("`GetModuleFileNameW` only supports the NULL handle");
                 }
 
diff --git a/src/tools/miri/src/shims/windows/fs.rs b/src/tools/miri/src/shims/windows/fs.rs
new file mode 100644
index 00000000000..32bab548969
--- /dev/null
+++ b/src/tools/miri/src/shims/windows/fs.rs
@@ -0,0 +1,402 @@
+use std::fs::{Metadata, OpenOptions};
+use std::io;
+use std::path::PathBuf;
+use std::time::SystemTime;
+
+use bitflags::bitflags;
+
+use crate::shims::files::{FileDescription, FileHandle};
+use crate::shims::windows::handle::{EvalContextExt as _, Handle};
+use crate::*;
+
+#[derive(Debug)]
+pub struct DirHandle {
+    pub(crate) path: PathBuf,
+}
+
+impl FileDescription for DirHandle {
+    fn name(&self) -> &'static str {
+        "directory"
+    }
+
+    fn metadata<'tcx>(&self) -> InterpResult<'tcx, io::Result<Metadata>> {
+        interp_ok(self.path.metadata())
+    }
+
+    fn close<'tcx>(
+        self,
+        _communicate_allowed: bool,
+        _ecx: &mut MiriInterpCx<'tcx>,
+    ) -> InterpResult<'tcx, io::Result<()>> {
+        interp_ok(Ok(()))
+    }
+}
+
+/// Windows supports handles without any read/write/delete permissions - these handles can get
+/// metadata, but little else. We represent that by storing the metadata from the time the handle
+/// was opened.
+#[derive(Debug)]
+pub struct MetadataHandle {
+    pub(crate) meta: Metadata,
+}
+
+impl FileDescription for MetadataHandle {
+    fn name(&self) -> &'static str {
+        "metadata-only"
+    }
+
+    fn metadata<'tcx>(&self) -> InterpResult<'tcx, io::Result<Metadata>> {
+        interp_ok(Ok(self.meta.clone()))
+    }
+
+    fn close<'tcx>(
+        self,
+        _communicate_allowed: bool,
+        _ecx: &mut MiriInterpCx<'tcx>,
+    ) -> InterpResult<'tcx, io::Result<()>> {
+        interp_ok(Ok(()))
+    }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+enum CreationDisposition {
+    CreateAlways,
+    CreateNew,
+    OpenAlways,
+    OpenExisting,
+    TruncateExisting,
+}
+
+impl CreationDisposition {
+    fn new<'tcx>(
+        value: u32,
+        ecx: &mut MiriInterpCx<'tcx>,
+    ) -> InterpResult<'tcx, CreationDisposition> {
+        let create_always = ecx.eval_windows_u32("c", "CREATE_ALWAYS");
+        let create_new = ecx.eval_windows_u32("c", "CREATE_NEW");
+        let open_always = ecx.eval_windows_u32("c", "OPEN_ALWAYS");
+        let open_existing = ecx.eval_windows_u32("c", "OPEN_EXISTING");
+        let truncate_existing = ecx.eval_windows_u32("c", "TRUNCATE_EXISTING");
+
+        let out = if value == create_always {
+            CreationDisposition::CreateAlways
+        } else if value == create_new {
+            CreationDisposition::CreateNew
+        } else if value == open_always {
+            CreationDisposition::OpenAlways
+        } else if value == open_existing {
+            CreationDisposition::OpenExisting
+        } else if value == truncate_existing {
+            CreationDisposition::TruncateExisting
+        } else {
+            throw_unsup_format!("CreateFileW: Unsupported creation disposition: {value}");
+        };
+        interp_ok(out)
+    }
+}
+
+bitflags! {
+    #[derive(PartialEq)]
+    struct FileAttributes: u32 {
+        const ZERO = 0;
+        const NORMAL = 1 << 0;
+        /// This must be passed to allow getting directory handles. If not passed, we error on trying
+        /// to open directories
+        const BACKUP_SEMANTICS = 1 << 1;
+        /// Open a reparse point as a regular file - this is basically similar to 'readlink' in Unix
+        /// terminology. A reparse point is a file with custom logic when navigated to, of which
+        /// a symlink is one specific example.
+        const OPEN_REPARSE = 1 << 2;
+    }
+}
+
+impl FileAttributes {
+    fn new<'tcx>(
+        mut value: u32,
+        ecx: &mut MiriInterpCx<'tcx>,
+    ) -> InterpResult<'tcx, FileAttributes> {
+        let file_attribute_normal = ecx.eval_windows_u32("c", "FILE_ATTRIBUTE_NORMAL");
+        let file_flag_backup_semantics = ecx.eval_windows_u32("c", "FILE_FLAG_BACKUP_SEMANTICS");
+        let file_flag_open_reparse_point =
+            ecx.eval_windows_u32("c", "FILE_FLAG_OPEN_REPARSE_POINT");
+
+        let mut out = FileAttributes::ZERO;
+        if value & file_flag_backup_semantics != 0 {
+            value &= !file_flag_backup_semantics;
+            out |= FileAttributes::BACKUP_SEMANTICS;
+        }
+        if value & file_flag_open_reparse_point != 0 {
+            value &= !file_flag_open_reparse_point;
+            out |= FileAttributes::OPEN_REPARSE;
+        }
+        if value & file_attribute_normal != 0 {
+            value &= !file_attribute_normal;
+            out |= FileAttributes::NORMAL;
+        }
+
+        if value != 0 {
+            throw_unsup_format!("CreateFileW: Unsupported flags_and_attributes: {value}");
+        }
+
+        if out == FileAttributes::ZERO {
+            // NORMAL is equivalent to 0. Avoid needing to check both cases by unifying the two.
+            out = FileAttributes::NORMAL;
+        }
+        interp_ok(out)
+    }
+}
+
+impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
+#[allow(non_snake_case)]
+pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
+    fn CreateFileW(
+        &mut self,
+        file_name: &OpTy<'tcx>,            // LPCWSTR
+        desired_access: &OpTy<'tcx>,       // DWORD
+        share_mode: &OpTy<'tcx>,           // DWORD
+        security_attributes: &OpTy<'tcx>,  // LPSECURITY_ATTRIBUTES
+        creation_disposition: &OpTy<'tcx>, // DWORD
+        flags_and_attributes: &OpTy<'tcx>, // DWORD
+        template_file: &OpTy<'tcx>,        // HANDLE
+    ) -> InterpResult<'tcx, Handle> {
+        // ^ Returns HANDLE
+        use CreationDisposition::*;
+
+        let this = self.eval_context_mut();
+        this.assert_target_os("windows", "CreateFileW");
+        this.check_no_isolation("`CreateFileW`")?;
+
+        // This function appears to always set the error to 0. This is important for some flag
+        // combinations, which may set error code on success.
+        this.set_last_error(IoError::Raw(Scalar::from_i32(0)))?;
+
+        let file_name = this.read_path_from_wide_str(this.read_pointer(file_name)?)?;
+        let mut desired_access = this.read_scalar(desired_access)?.to_u32()?;
+        let share_mode = this.read_scalar(share_mode)?.to_u32()?;
+        let security_attributes = this.read_pointer(security_attributes)?;
+        let creation_disposition = this.read_scalar(creation_disposition)?.to_u32()?;
+        let flags_and_attributes = this.read_scalar(flags_and_attributes)?.to_u32()?;
+        let template_file = this.read_target_usize(template_file)?;
+
+        let generic_read = this.eval_windows_u32("c", "GENERIC_READ");
+        let generic_write = this.eval_windows_u32("c", "GENERIC_WRITE");
+
+        let file_share_delete = this.eval_windows_u32("c", "FILE_SHARE_DELETE");
+        let file_share_read = this.eval_windows_u32("c", "FILE_SHARE_READ");
+        let file_share_write = this.eval_windows_u32("c", "FILE_SHARE_WRITE");
+
+        let creation_disposition = CreationDisposition::new(creation_disposition, this)?;
+        let attributes = FileAttributes::new(flags_and_attributes, this)?;
+
+        if share_mode != (file_share_delete | file_share_read | file_share_write) {
+            throw_unsup_format!("CreateFileW: Unsupported share mode: {share_mode}");
+        }
+        if !this.ptr_is_null(security_attributes)? {
+            throw_unsup_format!("CreateFileW: Security attributes are not supported");
+        }
+
+        if attributes.contains(FileAttributes::OPEN_REPARSE) && creation_disposition == CreateAlways
+        {
+            throw_machine_stop!(TerminationInfo::Abort("Invalid CreateFileW argument combination: FILE_FLAG_OPEN_REPARSE_POINT with CREATE_ALWAYS".to_string()));
+        }
+
+        if template_file != 0 {
+            throw_unsup_format!("CreateFileW: Template files are not supported");
+        }
+
+        // We need to know if the file is a directory to correctly open directory handles.
+        // This is racy, but currently the stdlib doesn't appear to offer a better solution.
+        let is_dir = file_name.is_dir();
+
+        // BACKUP_SEMANTICS is how Windows calls the act of opening a directory handle.
+        if !attributes.contains(FileAttributes::BACKUP_SEMANTICS) && is_dir {
+            this.set_last_error(IoError::WindowsError("ERROR_ACCESS_DENIED"))?;
+            return interp_ok(Handle::Invalid);
+        }
+
+        let desired_read = desired_access & generic_read != 0;
+        let desired_write = desired_access & generic_write != 0;
+
+        let mut options = OpenOptions::new();
+        if desired_read {
+            desired_access &= !generic_read;
+            options.read(true);
+        }
+        if desired_write {
+            desired_access &= !generic_write;
+            options.write(true);
+        }
+
+        if desired_access != 0 {
+            throw_unsup_format!(
+                "CreateFileW: Unsupported bits set for access mode: {desired_access:#x}"
+            );
+        }
+
+        // Per the documentation:
+        // If the specified file exists and is writable, the function truncates the file,
+        // the function succeeds, and last-error code is set to ERROR_ALREADY_EXISTS.
+        // If the specified file does not exist and is a valid path, a new file is created,
+        // the function succeeds, and the last-error code is set to zero.
+        // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
+        //
+        // This is racy, but there doesn't appear to be an std API that both succeeds if a
+        // file exists but tells us it isn't new. Either we accept racing one way or another,
+        // or we use an iffy heuristic like file creation time. This implementation prefers
+        // to fail in the direction of erroring more often.
+        if let CreateAlways | OpenAlways = creation_disposition
+            && file_name.exists()
+        {
+            this.set_last_error(IoError::WindowsError("ERROR_ALREADY_EXISTS"))?;
+        }
+
+        let handle = if is_dir {
+            // Open this as a directory.
+            let fd_num = this.machine.fds.insert_new(DirHandle { path: file_name });
+            Ok(Handle::File(fd_num))
+        } else if creation_disposition == OpenExisting && !(desired_read || desired_write) {
+            // Windows supports handles with no permissions. These allow things such as reading
+            // metadata, but not file content.
+            file_name.metadata().map(|meta| {
+                let fd_num = this.machine.fds.insert_new(MetadataHandle { meta });
+                Handle::File(fd_num)
+            })
+        } else {
+            // Open this as a standard file.
+            match creation_disposition {
+                CreateAlways | OpenAlways => {
+                    options.create(true);
+                    if creation_disposition == CreateAlways {
+                        options.truncate(true);
+                    }
+                }
+                CreateNew => {
+                    options.create_new(true);
+                    // Per `create_new` documentation:
+                    // The file must be opened with write or append access in order to create a new file.
+                    // https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.create_new
+                    if !desired_write {
+                        options.append(true);
+                    }
+                }
+                OpenExisting => {} // Default options
+                TruncateExisting => {
+                    options.truncate(true);
+                }
+            }
+
+            options.open(file_name).map(|file| {
+                let fd_num =
+                    this.machine.fds.insert_new(FileHandle { file, writable: desired_write });
+                Handle::File(fd_num)
+            })
+        };
+
+        match handle {
+            Ok(handle) => interp_ok(handle),
+            Err(e) => {
+                this.set_last_error(e)?;
+                interp_ok(Handle::Invalid)
+            }
+        }
+    }
+
+    fn GetFileInformationByHandle(
+        &mut self,
+        file: &OpTy<'tcx>,             // HANDLE
+        file_information: &OpTy<'tcx>, // LPBY_HANDLE_FILE_INFORMATION
+    ) -> InterpResult<'tcx, Scalar> {
+        // ^ Returns BOOL (i32 on Windows)
+        let this = self.eval_context_mut();
+        this.assert_target_os("windows", "GetFileInformationByHandle");
+        this.check_no_isolation("`GetFileInformationByHandle`")?;
+
+        let file = this.read_handle(file, "GetFileInformationByHandle")?;
+        let file_information = this.deref_pointer_as(
+            file_information,
+            this.windows_ty_layout("BY_HANDLE_FILE_INFORMATION"),
+        )?;
+
+        let fd_num = if let Handle::File(fd_num) = file {
+            fd_num
+        } else {
+            this.invalid_handle("GetFileInformationByHandle")?
+        };
+
+        let Some(desc) = this.machine.fds.get(fd_num) else {
+            this.invalid_handle("GetFileInformationByHandle")?
+        };
+
+        let metadata = match desc.metadata()? {
+            Ok(meta) => meta,
+            Err(e) => {
+                this.set_last_error(e)?;
+                return interp_ok(this.eval_windows("c", "FALSE"));
+            }
+        };
+
+        let size = metadata.len();
+
+        let file_type = metadata.file_type();
+        let attributes = if file_type.is_dir() {
+            this.eval_windows_u32("c", "FILE_ATTRIBUTE_DIRECTORY")
+        } else if file_type.is_file() {
+            this.eval_windows_u32("c", "FILE_ATTRIBUTE_NORMAL")
+        } else {
+            this.eval_windows_u32("c", "FILE_ATTRIBUTE_DEVICE")
+        };
+
+        // Per the Windows documentation:
+        // "If the underlying file system does not support the [...] time, this member is zero (0)."
+        // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/ns-fileapi-by_handle_file_information
+        let created = extract_windows_epoch(this, metadata.created())?.unwrap_or((0, 0));
+        let accessed = extract_windows_epoch(this, metadata.accessed())?.unwrap_or((0, 0));
+        let written = extract_windows_epoch(this, metadata.modified())?.unwrap_or((0, 0));
+
+        this.write_int_fields_named(&[("dwFileAttributes", attributes.into())], &file_information)?;
+        write_filetime_field(this, &file_information, "ftCreationTime", created)?;
+        write_filetime_field(this, &file_information, "ftLastAccessTime", accessed)?;
+        write_filetime_field(this, &file_information, "ftLastWriteTime", written)?;
+        this.write_int_fields_named(
+            &[
+                ("dwVolumeSerialNumber", 0),
+                ("nFileSizeHigh", (size >> 32).into()),
+                ("nFileSizeLow", (size & 0xFFFFFFFF).into()),
+                ("nNumberOfLinks", 1),
+                ("nFileIndexHigh", 0),
+                ("nFileIndexLow", 0),
+            ],
+            &file_information,
+        )?;
+
+        interp_ok(this.eval_windows("c", "TRUE"))
+    }
+}
+
+/// Windows FILETIME is measured in 100-nanosecs since 1601
+fn extract_windows_epoch<'tcx>(
+    ecx: &MiriInterpCx<'tcx>,
+    time: io::Result<SystemTime>,
+) -> InterpResult<'tcx, Option<(u32, u32)>> {
+    match time.ok() {
+        Some(time) => {
+            let duration = ecx.system_time_since_windows_epoch(&time)?;
+            let duration_ticks = ecx.windows_ticks_for(duration)?;
+            #[allow(clippy::cast_possible_truncation)]
+            interp_ok(Some((duration_ticks as u32, (duration_ticks >> 32) as u32)))
+        }
+        None => interp_ok(None),
+    }
+}
+
+fn write_filetime_field<'tcx>(
+    cx: &mut MiriInterpCx<'tcx>,
+    val: &MPlaceTy<'tcx>,
+    name: &str,
+    (low, high): (u32, u32),
+) -> InterpResult<'tcx> {
+    cx.write_int_fields_named(
+        &[("dwLowDateTime", low.into()), ("dwHighDateTime", high.into())],
+        &cx.project_field_named(val, name)?,
+    )
+}
diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs
index c4eb11fbd3f..eec6c62bebc 100644
--- a/src/tools/miri/src/shims/windows/handle.rs
+++ b/src/tools/miri/src/shims/windows/handle.rs
@@ -3,6 +3,7 @@ use std::mem::variant_count;
 use rustc_abi::HasDataLayout;
 
 use crate::concurrency::thread::ThreadNotFound;
+use crate::shims::files::FdNum;
 use crate::*;
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
@@ -16,6 +17,8 @@ pub enum Handle {
     Null,
     Pseudo(PseudoHandle),
     Thread(ThreadId),
+    File(FdNum),
+    Invalid,
 }
 
 impl PseudoHandle {
@@ -47,12 +50,18 @@ impl Handle {
     const NULL_DISCRIMINANT: u32 = 0;
     const PSEUDO_DISCRIMINANT: u32 = 1;
     const THREAD_DISCRIMINANT: u32 = 2;
+    const FILE_DISCRIMINANT: u32 = 3;
+    // Chosen to ensure Handle::Invalid encodes to -1. Update this value if there are ever more than
+    // 8 discriminants.
+    const INVALID_DISCRIMINANT: u32 = 7;
 
     fn discriminant(self) -> u32 {
         match self {
             Self::Null => Self::NULL_DISCRIMINANT,
             Self::Pseudo(_) => Self::PSEUDO_DISCRIMINANT,
             Self::Thread(_) => Self::THREAD_DISCRIMINANT,
+            Self::File(_) => Self::FILE_DISCRIMINANT,
+            Self::Invalid => Self::INVALID_DISCRIMINANT,
         }
     }
 
@@ -61,17 +70,27 @@ impl Handle {
             Self::Null => 0,
             Self::Pseudo(pseudo_handle) => pseudo_handle.value(),
             Self::Thread(thread) => thread.to_u32(),
+            #[expect(clippy::cast_sign_loss)]
+            Self::File(fd) => fd as u32,
+            // INVALID_HANDLE_VALUE is -1. This fact is explicitly declared or implied in several
+            // pages of Windows documentation.
+            // 1: https://learn.microsoft.com/en-us/dotnet/api/microsoft.win32.safehandles.safefilehandle?view=net-9.0
+            // 2: https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle?view=msvc-170
+            Self::Invalid => 0x1FFFFFFF,
         }
     }
 
     fn packed_disc_size() -> u32 {
-        // ceil(log2(x)) is how many bits it takes to store x numbers
+        // ceil(log2(x)) is how many bits it takes to store x numbers.
+        // We ensure that INVALID_HANDLE_VALUE (0xFFFFFFFF) decodes to Handle::Invalid.
+        // see https://devblogs.microsoft.com/oldnewthing/20230914-00/?p=108766 for more detail on
+        // INVALID_HANDLE_VALUE.
         let variant_count = variant_count::<Self>();
 
-        // however, std's ilog2 is floor(log2(x))
+        // However, std's ilog2 is floor(log2(x)).
         let floor_log2 = variant_count.ilog2();
 
-        // we need to add one for non powers of two to compensate for the difference
+        // We need to add one for non powers of two to compensate for the difference.
         #[expect(clippy::arithmetic_side_effects)] // cannot overflow
         if variant_count.is_power_of_two() { floor_log2 } else { floor_log2 + 1 }
     }
@@ -105,6 +124,13 @@ impl Handle {
             Self::NULL_DISCRIMINANT if data == 0 => Some(Self::Null),
             Self::PSEUDO_DISCRIMINANT => Some(Self::Pseudo(PseudoHandle::from_value(data)?)),
             Self::THREAD_DISCRIMINANT => Some(Self::Thread(ThreadId::new_unchecked(data))),
+            #[expect(clippy::cast_possible_wrap)]
+            Self::FILE_DISCRIMINANT => {
+                // This cast preserves all bits.
+                assert_eq!(size_of_val(&data), size_of::<FdNum>());
+                Some(Self::File(data as FdNum))
+            }
+            Self::INVALID_DISCRIMINANT => Some(Self::Invalid),
             _ => None,
         }
     }
@@ -139,7 +165,7 @@ 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`].
-    pub fn try_from_scalar<'tcx>(
+    fn try_from_scalar<'tcx>(
         handle: Scalar,
         cx: &MiriInterpCx<'tcx>,
     ) -> InterpResult<'tcx, Result<Self, HandleError>> {
@@ -171,6 +197,27 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
 
 #[allow(non_snake_case)]
 pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
+    /// Convert a scalar into a structured `Handle`.
+    /// If the handle is invalid, or references a non-existent item, execution is aborted.
+    #[track_caller]
+    fn read_handle(&self, handle: &OpTy<'tcx>, function_name: &str) -> InterpResult<'tcx, Handle> {
+        let this = self.eval_context_ref();
+        let handle = this.read_scalar(handle)?;
+        match Handle::try_from_scalar(handle, this)? {
+            Ok(handle) => interp_ok(handle),
+            Err(HandleError::InvalidHandle) =>
+                throw_machine_stop!(TerminationInfo::Abort(format!(
+                    "invalid handle {} passed to {function_name}",
+                    handle.to_target_isize(this)?,
+                ))),
+            Err(HandleError::ThreadNotFound(_)) =>
+                throw_machine_stop!(TerminationInfo::Abort(format!(
+                    "invalid thread ID {} passed to {function_name}",
+                    handle.to_target_isize(this)?,
+                ))),
+        }
+    }
+
     fn invalid_handle(&mut self, function_name: &str) -> InterpResult<'tcx, !> {
         throw_machine_stop!(TerminationInfo::Abort(format!(
             "invalid handle passed to `{function_name}`"
@@ -180,15 +227,38 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn CloseHandle(&mut self, handle_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
-        let handle = this.read_scalar(handle_op)?;
-        let ret = match Handle::try_from_scalar(handle, this)? {
-            Ok(Handle::Thread(thread)) => {
+        let handle = this.read_handle(handle_op, "CloseHandle")?;
+        let ret = match handle {
+            Handle::Thread(thread) => {
                 this.detach_thread(thread, /*allow_terminated_joined*/ true)?;
                 this.eval_windows("c", "TRUE")
             }
+            Handle::File(fd_num) =>
+                if let Some(fd) = this.machine.fds.remove(fd_num) {
+                    let err = fd.close_ref(this.machine.communicate(), this)?;
+                    if let Err(e) = err {
+                        this.set_last_error(e)?;
+                        this.eval_windows("c", "FALSE")
+                    } else {
+                        this.eval_windows("c", "TRUE")
+                    }
+                } else {
+                    this.invalid_handle("CloseHandle")?
+                },
             _ => this.invalid_handle("CloseHandle")?,
         };
 
         interp_ok(ret)
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_invalid_encoding() {
+        // Ensure the invalid handle encodes to `u32::MAX`/`INVALID_HANDLE_VALUE`.
+        assert_eq!(Handle::Invalid.to_packed(), u32::MAX)
+    }
+}
diff --git a/src/tools/miri/src/shims/windows/mod.rs b/src/tools/miri/src/shims/windows/mod.rs
index 892bd6924fc..442c5a0dd11 100644
--- a/src/tools/miri/src/shims/windows/mod.rs
+++ b/src/tools/miri/src/shims/windows/mod.rs
@@ -1,12 +1,14 @@
 pub mod foreign_items;
 
 mod env;
+mod fs;
 mod handle;
 mod sync;
 mod thread;
 
 // All the Windows-specific extension traits
 pub use self::env::{EvalContextExt as _, WindowsEnvVars};
+pub use self::fs::EvalContextExt as _;
 pub use self::handle::EvalContextExt as _;
 pub use self::sync::EvalContextExt as _;
 pub use self::thread::EvalContextExt as _;
diff --git a/src/tools/miri/src/shims/windows/thread.rs b/src/tools/miri/src/shims/windows/thread.rs
index 5db55404422..d5f9ed4e968 100644
--- a/src/tools/miri/src/shims/windows/thread.rs
+++ b/src/tools/miri/src/shims/windows/thread.rs
@@ -62,14 +62,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
-        let handle = this.read_scalar(handle_op)?;
+        let handle = this.read_handle(handle_op, "WaitForSingleObject")?;
         let timeout = this.read_scalar(timeout_op)?.to_u32()?;
 
-        let thread = match Handle::try_from_scalar(handle, this)? {
-            Ok(Handle::Thread(thread)) => thread,
+        let thread = 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.
-            Ok(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.active_thread(),
+            Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
             _ => this.invalid_handle("WaitForSingleObject")?,
         };
 
diff --git a/src/tools/miri/test-cargo-miri/Cargo.lock b/src/tools/miri/test-cargo-miri/Cargo.lock
index 8f618e7ffb3..32119426184 100644
--- a/src/tools/miri/test-cargo-miri/Cargo.lock
+++ b/src/tools/miri/test-cargo-miri/Cargo.lock
@@ -1,12 +1,12 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
-version = 3
+version = 4
 
 [[package]]
 name = "autocfg"
-version = "1.2.0"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
 
 [[package]]
 name = "byteorder"
@@ -96,15 +96,15 @@ version = "0.1.0"
 
 [[package]]
 name = "once_cell"
-version = "1.19.0"
+version = "1.21.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.79"
+version = "1.0.94"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
+checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
 dependencies = [
  "unicode-ident",
 ]
@@ -129,6 +129,6 @@ version = "0.1.0"
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.12"
+version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
diff --git a/src/tools/miri/test-cargo-miri/Cargo.toml b/src/tools/miri/test-cargo-miri/Cargo.toml
index 574f1d05a6f..f5092a4748f 100644
--- a/src/tools/miri/test-cargo-miri/Cargo.toml
+++ b/src/tools/miri/test-cargo-miri/Cargo.toml
@@ -6,7 +6,7 @@ exclude = ["no-std-smoke"] # it wants to be panic="abort"
 name = "cargo-miri-test"
 version = "0.1.0"
 authors = ["Miri Team"]
-edition = "2018"
+edition = "2024"
 
 [dependencies]
 byteorder = "1.0"
diff --git a/src/tools/miri/test-cargo-miri/run-test.py b/src/tools/miri/test-cargo-miri/run-test.py
index 5b77092979d..a9d09ac7a9d 100755
--- a/src/tools/miri/test-cargo-miri/run-test.py
+++ b/src/tools/miri/test-cargo-miri/run-test.py
@@ -136,7 +136,7 @@ def test_cargo_miri_run():
         cargo_miri("run") + ["--target-dir=custom-run", "--", "--target-dir=target/custom-run"],
         "run.args.stdout.ref", "run.custom-target-dir.stderr.ref",
     )
-    test("`cargo miri run --package=test-local-crate-detection` (test local crate detection)",
+    test("`cargo miri run` (test local crate detection)",
          cargo_miri("run") + ["--package=test-local-crate-detection"],
          "run.local_crate.stdout.ref", "run.local_crate.stderr.ref",
     )
@@ -147,49 +147,46 @@ def test_cargo_miri_test():
     default_ref = "test.cross-target.stdout.ref" if is_foreign else "test.default.stdout.ref"
     filter_ref = "test.filter.cross-target.stdout.ref" if is_foreign else "test.filter.stdout.ref"
 
-    # macOS needs permissive provenance inside getrandom_1.
     test("`cargo miri test`",
         cargo_miri("test"),
-        default_ref, "test.stderr-empty.ref",
-        env={'MIRIFLAGS': "-Zmiri-permissive-provenance -Zmiri-seed=4242"},
+        default_ref, "test.empty.ref",
+        env={'MIRIFLAGS': "-Zmiri-seed=4242"},
     )
     test("`cargo miri test` (no isolation, no doctests)",
         cargo_miri("test") + ["--bins", "--tests"], # no `--lib`, we disabled that in `Cargo.toml`
-        "test.cross-target.stdout.ref", "test.stderr-empty.ref",
-        env={'MIRIFLAGS': "-Zmiri-permissive-provenance -Zmiri-disable-isolation"},
+        "test.cross-target.stdout.ref", "test.empty.ref",
+        env={'MIRIFLAGS': "-Zmiri-disable-isolation"},
     )
     test("`cargo miri test` (with filter)",
         cargo_miri("test") + ["--", "--format=pretty", "pl"],
-        filter_ref, "test.stderr-empty.ref",
+        filter_ref, "test.empty.ref",
     )
     test("`cargo miri test` (test target)",
         cargo_miri("test") + ["--test", "test", "--", "--format=pretty"],
-        "test.test-target.stdout.ref", "test.stderr-empty.ref",
-        env={'MIRIFLAGS': "-Zmiri-permissive-provenance"},
+        "test.test-target.stdout.ref", "test.empty.ref",
     )
     test("`cargo miri test` (bin target)",
         cargo_miri("test") + ["--bin", "cargo-miri-test", "--", "--format=pretty"],
-        "test.bin-target.stdout.ref", "test.stderr-empty.ref",
+        "test.bin-target.stdout.ref", "test.empty.ref",
     )
     test("`cargo miri t` (subcrate, no isolation)",
         cargo_miri("t") + ["-p", "subcrate"],
-        "test.subcrate.stdout.ref", "test.stderr-proc-macro.ref",
+        "test.subcrate.cross-target.stdout.ref" if is_foreign else "test.subcrate.stdout.ref",
+        "test.empty.ref",
         env={'MIRIFLAGS': "-Zmiri-disable-isolation"},
     )
-    test("`cargo miri test` (subcrate, doctests)",
-        cargo_miri("test") + ["-p", "subcrate", "--doc"],
-        "test.stdout-empty.ref", "test.stderr-proc-macro-doctest.ref",
+    test("`cargo miri test` (proc-macro crate)",
+        cargo_miri("test") + ["-p", "proc_macro_crate"],
+        "test.empty.ref", "test.proc-macro.stderr.ref",
     )
     test("`cargo miri test` (custom target dir)",
         cargo_miri("test") + ["--target-dir=custom-test"],
-        default_ref, "test.stderr-empty.ref",
-        env={'MIRIFLAGS': "-Zmiri-permissive-provenance"},
+        default_ref, "test.empty.ref",
     )
     del os.environ["CARGO_TARGET_DIR"] # this overrides `build.target-dir` passed by `--config`, so unset it
     test("`cargo miri test` (config-cli)",
         cargo_miri("test") + ["--config=build.target-dir=\"config-cli\""],
-        default_ref, "test.stderr-empty.ref",
-        env={'MIRIFLAGS': "-Zmiri-permissive-provenance"},
+        default_ref, "test.empty.ref",
     )
     if ARGS.multi_target:
         test_cargo_miri_multi_target()
@@ -198,8 +195,7 @@ def test_cargo_miri_test():
 def test_cargo_miri_multi_target():
     test("`cargo miri test` (multiple targets)",
         cargo_miri("test", targets = ["aarch64-unknown-linux-gnu", "s390x-unknown-linux-gnu"]),
-        "test.multiple_targets.stdout.ref", "test.stderr-empty.ref",
-        env={'MIRIFLAGS': "-Zmiri-permissive-provenance"},
+        "test.multiple_targets.stdout.ref", "test.empty.ref",
     )
 
 args_parser = argparse.ArgumentParser(description='`cargo miri` testing')
diff --git a/src/tools/miri/test-cargo-miri/src/lib.rs b/src/tools/miri/test-cargo-miri/src/lib.rs
index 003341d0974..3b63f8afc90 100644
--- a/src/tools/miri/test-cargo-miri/src/lib.rs
+++ b/src/tools/miri/test-cargo-miri/src/lib.rs
@@ -26,7 +26,8 @@
 ///
 /// let _val = Fail::<i32>::C;
 /// ```
-#[no_mangle]
+// This is imported in `main.rs`.
+#[unsafe(no_mangle)]
 pub fn make_true() -> bool {
     proc_macro_crate::use_the_dependency!();
     issue_1567::use_the_dependency();
diff --git a/src/tools/miri/test-cargo-miri/src/main.rs b/src/tools/miri/test-cargo-miri/src/main.rs
index efe95bf3aba..00a239a9161 100644
--- a/src/tools/miri/test-cargo-miri/src/main.rs
+++ b/src/tools/miri/test-cargo-miri/src/main.rs
@@ -30,7 +30,7 @@ fn main() {
             let mut out = Vec::with_capacity(1024);
 
             unsafe {
-                extern "Rust" {
+                unsafe extern "Rust" {
                     fn miri_host_to_target_path(
                         path: *const c_char,
                         out: *mut c_char,
@@ -81,7 +81,7 @@ mod test {
         // Test calling exported symbols in (transitive) dependencies.
         // Repeat calls to make sure the `Instance` cache is not broken.
         for _ in 0..3 {
-            extern "Rust" {
+            unsafe extern "Rust" {
                 fn exported_symbol() -> i32;
                 fn assoc_fn_as_exported_symbol() -> i32;
                 fn make_true() -> bool;
diff --git a/src/tools/miri/test-cargo-miri/subcrate/Cargo.toml b/src/tools/miri/test-cargo-miri/subcrate/Cargo.toml
index 06b1ce1cba4..f2f6360f2d2 100644
--- a/src/tools/miri/test-cargo-miri/subcrate/Cargo.toml
+++ b/src/tools/miri/test-cargo-miri/subcrate/Cargo.toml
@@ -2,11 +2,11 @@
 name = "subcrate"
 version = "0.1.0"
 authors = ["Miri Team"]
+# This is deliberately *not* on the 2024 edition to ensure doctests keep working
+# on old editions.
 edition = "2018"
 
 [lib]
-proc-macro = true
-doctest = false
 
 [[bin]]
 name = "subcrate"
diff --git a/src/tools/miri/test-cargo-miri/subcrate/src/lib.rs b/src/tools/miri/test-cargo-miri/subcrate/src/lib.rs
index 98c22fef076..b9278c54dbe 100644
--- a/src/tools/miri/test-cargo-miri/subcrate/src/lib.rs
+++ b/src/tools/miri/test-cargo-miri/subcrate/src/lib.rs
@@ -1,16 +1,8 @@
-// This is a proc-macro crate.
-
-extern crate proc_macro; // make sure proc_macro is in the sysroot
-
-#[cfg(doctest)]
-compile_error!("rustdoc should not touch me");
-
-#[cfg(miri)]
-compile_error!("Miri should not touch me");
-
-use proc_macro::TokenStream;
-
-#[proc_macro]
-pub fn make_answer(_item: TokenStream) -> TokenStream {
-    "fn answer() -> u32 { 42 }".parse().unwrap()
+/// Doc-test test
+///
+/// ```rust
+/// assert!(subcrate::make_true());
+/// ```
+pub fn make_true() -> bool {
+    true
 }
diff --git a/src/tools/miri/test-cargo-miri/test.stderr-empty.ref b/src/tools/miri/test-cargo-miri/test.empty.ref
index e69de29bb2d..e69de29bb2d 100644
--- a/src/tools/miri/test-cargo-miri/test.stderr-empty.ref
+++ b/src/tools/miri/test-cargo-miri/test.empty.ref
diff --git a/src/tools/miri/test-cargo-miri/test.stderr-proc-macro.ref b/src/tools/miri/test-cargo-miri/test.proc-macro.stderr.ref
index 4983250917b..b95474208b2 100644
--- a/src/tools/miri/test-cargo-miri/test.stderr-proc-macro.ref
+++ b/src/tools/miri/test-cargo-miri/test.proc-macro.stderr.ref
@@ -1 +1,2 @@
 Running unit tests of `proc-macro` crates is not currently supported by Miri.
+Running doctests of `proc-macro` crates is not currently supported by Miri.
diff --git a/src/tools/miri/test-cargo-miri/test.stderr-proc-macro-doctest.ref b/src/tools/miri/test-cargo-miri/test.stderr-proc-macro-doctest.ref
deleted file mode 100644
index ca5e3a2392d..00000000000
--- a/src/tools/miri/test-cargo-miri/test.stderr-proc-macro-doctest.ref
+++ /dev/null
@@ -1 +0,0 @@
-Running doctests of `proc-macro` crates is not currently supported by Miri.
diff --git a/src/tools/miri/test-cargo-miri/test.stdout-empty.ref b/src/tools/miri/test-cargo-miri/test.stdout-empty.ref
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/src/tools/miri/test-cargo-miri/test.stdout-empty.ref
+++ /dev/null
diff --git a/src/tools/miri/test-cargo-miri/test.subcrate.cross-target.stdout.ref b/src/tools/miri/test-cargo-miri/test.subcrate.cross-target.stdout.ref
new file mode 100644
index 00000000000..436e6e4fbbb
--- /dev/null
+++ b/src/tools/miri/test-cargo-miri/test.subcrate.cross-target.stdout.ref
@@ -0,0 +1,11 @@
+
+running 0 tests
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
+
+running 0 tests
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
+subcrate testing
diff --git a/src/tools/miri/test-cargo-miri/test.subcrate.stdout.ref b/src/tools/miri/test-cargo-miri/test.subcrate.stdout.ref
index e50838ebc83..c7c7bc8351b 100644
--- a/src/tools/miri/test-cargo-miri/test.subcrate.stdout.ref
+++ b/src/tools/miri/test-cargo-miri/test.subcrate.stdout.ref
@@ -3,4 +3,14 @@ running 0 tests
 
 test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
+
+running 0 tests
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
 subcrate testing
+
+running 1 test
+.
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock
index af92f9d0dec..276c518e74f 100644
--- a/src/tools/miri/test_dependencies/Cargo.lock
+++ b/src/tools/miri/test_dependencies/Cargo.lock
@@ -4,60 +4,51 @@ version = 4
 
 [[package]]
 name = "addr2line"
-version = "0.22.0"
+version = "0.24.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
+checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
 dependencies = [
  "gimli",
 ]
 
 [[package]]
-name = "adler"
-version = "1.0.2"
+name = "adler2"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
 
 [[package]]
 name = "backtrace"
-version = "0.3.73"
+version = "0.3.74"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"
+checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
 dependencies = [
  "addr2line",
- "cc",
  "cfg-if",
  "libc",
  "miniz_oxide",
  "object",
  "rustc-demangle",
+ "windows-targets",
 ]
 
 [[package]]
 name = "bitflags"
-version = "2.6.0"
+version = "2.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
 
 [[package]]
 name = "bumpalo"
-version = "3.16.0"
+version = "3.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
+checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
 
 [[package]]
 name = "bytes"
-version = "1.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"
-
-[[package]]
-name = "cc"
-version = "1.1.22"
+version = "1.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0"
-dependencies = [
- "shlex",
-]
+checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
 
 [[package]]
 name = "cfg-if"
@@ -67,19 +58,19 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "errno"
-version = "0.3.9"
+version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
+checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
 dependencies = [
  "libc",
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
 name = "fastrand"
-version = "2.1.0"
+version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
 
 [[package]]
 name = "getrandom"
@@ -107,21 +98,21 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.3.1"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
+checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
 dependencies = [
  "cfg-if",
  "libc",
- "wasi 0.13.3+wasi-0.2.2",
- "windows-targets",
+ "r-efi",
+ "wasi 0.14.2+wasi-0.2.4",
 ]
 
 [[package]]
 name = "gimli"
-version = "0.29.0"
+version = "0.31.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
+checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
 
 [[package]]
 name = "hermit-abi"
@@ -131,30 +122,31 @@ checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
 
 [[package]]
 name = "js-sys"
-version = "0.3.69"
+version = "0.3.77"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
+checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
 dependencies = [
+ "once_cell",
  "wasm-bindgen",
 ]
 
 [[package]]
 name = "libc"
-version = "0.2.161"
+version = "0.2.171"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
+checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.14"
+version = "0.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
 
 [[package]]
 name = "log"
-version = "0.4.22"
+version = "0.4.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
 
 [[package]]
 name = "memchr"
@@ -164,23 +156,22 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.7.4"
+version = "0.8.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
+checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
 dependencies = [
- "adler",
+ "adler2",
 ]
 
 [[package]]
 name = "mio"
-version = "1.0.1"
+version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4"
+checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
 dependencies = [
- "hermit-abi",
  "libc",
  "wasi 0.11.0+wasi-snapshot-preview1",
- "windows-sys",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -190,13 +181,13 @@ dependencies = [
  "cfg-if",
  "getrandom 0.1.16",
  "getrandom 0.2.15",
- "getrandom 0.3.1",
+ "getrandom 0.3.2",
  "libc",
  "num_cpus",
  "page_size",
  "tempfile",
  "tokio",
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -211,18 +202,18 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.36.2"
+version = "0.36.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e"
+checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "once_cell"
-version = "1.19.0"
+version = "1.21.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
 
 [[package]]
 name = "page_size"
@@ -236,29 +227,35 @@ dependencies = [
 
 [[package]]
 name = "pin-project-lite"
-version = "0.2.14"
+version = "0.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
+checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.86"
+version = "1.0.94"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.36"
+version = "1.0.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
 dependencies = [
  "proc-macro2",
 ]
 
 [[package]]
+name = "r-efi"
+version = "5.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
+
+[[package]]
 name = "rustc-demangle"
 version = "0.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -266,24 +263,18 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
 
 [[package]]
 name = "rustix"
-version = "0.38.34"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
+checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
 dependencies = [
  "bitflags",
  "errno",
  "libc",
  "linux-raw-sys",
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
-name = "shlex"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
-
-[[package]]
 name = "signal-hook-registry"
 version = "1.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -294,19 +285,19 @@ dependencies = [
 
 [[package]]
 name = "socket2"
-version = "0.5.7"
+version = "0.5.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
+checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef"
 dependencies = [
  "libc",
- "windows-sys",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "syn"
-version = "2.0.72"
+version = "2.0.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
+checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -315,22 +306,22 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.11.0"
+version = "3.19.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53"
+checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf"
 dependencies = [
- "cfg-if",
  "fastrand",
+ "getrandom 0.3.2",
  "once_cell",
  "rustix",
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
 name = "tokio"
-version = "1.39.2"
+version = "1.44.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1"
+checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
 dependencies = [
  "backtrace",
  "bytes",
@@ -340,14 +331,14 @@ dependencies = [
  "signal-hook-registry",
  "socket2",
  "tokio-macros",
- "windows-sys",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "tokio-macros"
-version = "2.4.0"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
+checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -356,9 +347,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.12"
+version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
 
 [[package]]
 name = "wasi"
@@ -374,32 +365,32 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasi"
-version = "0.13.3+wasi-0.2.2"
+version = "0.14.2+wasi-0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
+checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
 dependencies = [
  "wit-bindgen-rt",
 ]
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.92"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
 dependencies = [
  "cfg-if",
+ "once_cell",
  "wasm-bindgen-macro",
 ]
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.92"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
+checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
 dependencies = [
  "bumpalo",
  "log",
- "once_cell",
  "proc-macro2",
  "quote",
  "syn",
@@ -408,9 +399,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.92"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
+checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -418,9 +409,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.92"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
+checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -431,9 +422,12 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.92"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
+checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+dependencies = [
+ "unicode-ident",
+]
 
 [[package]]
 name = "winapi"
@@ -467,6 +461,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
 name = "windows-targets"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -532,9 +535,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
 name = "wit-bindgen-rt"
-version = "0.33.0"
+version = "0.39.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
+checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
 dependencies = [
  "bitflags",
 ]
diff --git a/src/tools/miri/test_dependencies/Cargo.toml b/src/tools/miri/test_dependencies/Cargo.toml
index 78dddaf11df..653228a5e3d 100644
--- a/src/tools/miri/test_dependencies/Cargo.toml
+++ b/src/tools/miri/test_dependencies/Cargo.toml
@@ -22,9 +22,9 @@ tempfile = "3"
 page_size = "0.6"
 # Avoid pulling in all of tokio's dependencies.
 # However, without `net` and `signal`, tokio uses fewer relevant system APIs.
-tokio = { version = "1.24", features = ["macros", "rt-multi-thread", "time", "net", "fs", "sync", "signal", "io-util"] }
+tokio = { version = "1", features = ["macros", "rt-multi-thread", "time", "net", "fs", "sync", "signal", "io-util"] }
 
 [target.'cfg(windows)'.dependencies]
-windows-sys = { version = "0.52", features = [ "Win32_Foundation", "Win32_System_Threading" ] }
+windows-sys = { version = "0.59", features = ["Win32_Foundation", "Win32_System_Threading", "Win32_Storage_FileSystem", "Win32_Security"] }
 
 [workspace]
diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs
index 279201df867..3ee2bf14f9f 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs
@@ -13,7 +13,7 @@ use windows_sys::Win32::System::Threading::{INFINITE, WaitForSingleObject};
 // XXX HACK: This is how miri represents the handle for thread 0.
 // This value can be "legitimately" obtained by using `GetCurrentThread` with `DuplicateHandle`
 // but miri does not implement `DuplicateHandle` yet.
-const MAIN_THREAD: HANDLE = (2i32 << 30) as HANDLE;
+const MAIN_THREAD: HANDLE = (2i32 << 29) as HANDLE;
 
 fn main() {
     thread::spawn(|| {
diff --git a/src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs
new file mode 100644
index 00000000000..38a0bf58148
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs
@@ -0,0 +1,260 @@
+//@only-target: freebsd
+//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-isolation
+
+use std::mem::{self, MaybeUninit};
+use std::ptr::{self, addr_of};
+use std::sync::atomic::AtomicU32;
+use std::time::Instant;
+use std::{io, thread};
+
+fn wait_wake() {
+    fn wake_nobody() {
+        // Current thread waits on futex.
+        // New thread wakes up 0 threads waiting on that futex.
+        // Current thread should time out.
+        static mut FUTEX: u32 = 0;
+
+        let waker = thread::spawn(|| {
+            unsafe {
+                assert_eq!(
+                    libc::_umtx_op(
+                        addr_of!(FUTEX) as *mut _,
+                        libc::UMTX_OP_WAKE_PRIVATE,
+                        0, // wake up 0 waiters
+                        ptr::null_mut::<libc::c_void>(),
+                        ptr::null_mut::<libc::c_void>(),
+                    ),
+                    0
+                );
+            }
+        });
+
+        // 10ms should be enough.
+        let mut timeout = libc::timespec { tv_sec: 0, tv_nsec: 10_000_000 };
+        let timeout_size_arg =
+            ptr::without_provenance_mut::<libc::c_void>(mem::size_of::<libc::timespec>());
+        unsafe {
+            assert_eq!(
+                libc::_umtx_op(
+                    addr_of!(FUTEX) as *mut _,
+                    libc::UMTX_OP_WAIT_UINT_PRIVATE,
+                    0,
+                    timeout_size_arg,
+                    &mut timeout as *mut _ as _,
+                ),
+                -1
+            );
+            // Main thread did not get woken up, so it timed out.
+            assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::ETIMEDOUT);
+        }
+
+        waker.join().unwrap();
+    }
+
+    fn wake_two_of_three() {
+        // We create 2 threads that wait on a futex with a 100ms timeout.
+        // The main thread wakes up 2 threads waiting on this futex and after this
+        // checks that only those threads woke up and the other one timed out.
+        static mut FUTEX: u32 = 0;
+
+        fn waiter() -> bool {
+            let mut timeout = libc::timespec { tv_sec: 0, tv_nsec: 100_000_000 };
+            let timeout_size_arg =
+                ptr::without_provenance_mut::<libc::c_void>(mem::size_of::<libc::timespec>());
+            unsafe {
+                libc::_umtx_op(
+                    addr_of!(FUTEX) as *mut _,
+                    libc::UMTX_OP_WAIT_UINT_PRIVATE,
+                    0, // FUTEX is 0
+                    timeout_size_arg,
+                    &mut timeout as *mut _ as _,
+                );
+                // Return true if this thread woke up.
+                io::Error::last_os_error().raw_os_error().unwrap() != libc::ETIMEDOUT
+            }
+        }
+
+        let t1 = thread::spawn(waiter);
+        let t2 = thread::spawn(waiter);
+        let t3 = thread::spawn(waiter);
+
+        // Run all the waiters, so they can go to sleep.
+        thread::yield_now();
+
+        // Wake up 2 thread and make sure 1 is still waiting.
+        unsafe {
+            assert_eq!(
+                libc::_umtx_op(
+                    addr_of!(FUTEX) as *mut _,
+                    libc::UMTX_OP_WAKE_PRIVATE,
+                    2,
+                    ptr::null_mut::<libc::c_void>(),
+                    ptr::null_mut::<libc::c_void>(),
+                ),
+                0
+            );
+        }
+
+        // Treat the booleans as numbers to simplify checking how many threads were woken up.
+        let t1 = t1.join().unwrap() as usize;
+        let t2 = t2.join().unwrap() as usize;
+        let t3 = t3.join().unwrap() as usize;
+        let woken_up_count = t1 + t2 + t3;
+        assert!(woken_up_count == 2, "Expected 2 threads to wake up got: {woken_up_count}");
+    }
+
+    wake_nobody();
+    wake_two_of_three();
+}
+
+fn wake_dangling() {
+    let futex = Box::new(0);
+    let ptr: *const u32 = &*futex;
+    drop(futex);
+
+    // Expect error since this is now "unmapped" memory.
+    unsafe {
+        assert_eq!(
+            libc::_umtx_op(
+                ptr as *const AtomicU32 as *mut _,
+                libc::UMTX_OP_WAKE_PRIVATE,
+                0,
+                ptr::null_mut::<libc::c_void>(),
+                ptr::null_mut::<libc::c_void>(),
+            ),
+            -1
+        );
+        assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::EFAULT);
+    }
+}
+
+fn wait_wrong_val() {
+    let futex: u32 = 123;
+
+    // Wait with a wrong value just returns 0
+    unsafe {
+        assert_eq!(
+            libc::_umtx_op(
+                ptr::from_ref(&futex).cast_mut().cast(),
+                libc::UMTX_OP_WAIT_UINT_PRIVATE,
+                456,
+                ptr::null_mut::<libc::c_void>(),
+                ptr::null_mut::<libc::c_void>(),
+            ),
+            0
+        );
+    }
+}
+
+fn wait_relative_timeout() {
+    fn without_timespec() {
+        let start = Instant::now();
+
+        let futex: u32 = 123;
+
+        let mut timeout = libc::timespec { tv_sec: 0, tv_nsec: 200_000_000 };
+        let timeout_size_arg =
+            ptr::without_provenance_mut::<libc::c_void>(mem::size_of::<libc::timespec>());
+        // Wait for 200ms, with nobody waking us up early
+        unsafe {
+            assert_eq!(
+                libc::_umtx_op(
+                    ptr::from_ref(&futex).cast_mut().cast(),
+                    libc::UMTX_OP_WAIT_UINT_PRIVATE,
+                    123,
+                    timeout_size_arg,
+                    &mut timeout as *mut _ as _,
+                ),
+                -1
+            );
+            assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::ETIMEDOUT);
+        }
+
+        assert!((200..1000).contains(&start.elapsed().as_millis()));
+    }
+
+    fn with_timespec() {
+        let futex: u32 = 123;
+        let mut timeout = libc::_umtx_time {
+            _timeout: libc::timespec { tv_sec: 0, tv_nsec: 200_000_000 },
+            _flags: 0,
+            _clockid: libc::CLOCK_MONOTONIC as u32,
+        };
+        let timeout_size_arg =
+            ptr::without_provenance_mut::<libc::c_void>(mem::size_of::<libc::_umtx_time>());
+
+        let start = Instant::now();
+
+        // Wait for 200ms, with nobody waking us up early
+        unsafe {
+            assert_eq!(
+                libc::_umtx_op(
+                    ptr::from_ref(&futex).cast_mut().cast(),
+                    libc::UMTX_OP_WAIT_UINT_PRIVATE,
+                    123,
+                    timeout_size_arg,
+                    &mut timeout as *mut _ as _,
+                ),
+                -1
+            );
+            assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::ETIMEDOUT);
+        }
+        assert!((200..1000).contains(&start.elapsed().as_millis()));
+    }
+
+    without_timespec();
+    with_timespec();
+}
+
+fn wait_absolute_timeout() {
+    let start = Instant::now();
+
+    // Get the current monotonic timestamp as timespec.
+    let mut timeout = unsafe {
+        let mut now: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
+        assert_eq!(libc::clock_gettime(libc::CLOCK_MONOTONIC, now.as_mut_ptr()), 0);
+        now.assume_init()
+    };
+
+    // Add 200ms.
+    timeout.tv_nsec += 200_000_000;
+    if timeout.tv_nsec > 1_000_000_000 {
+        timeout.tv_nsec -= 1_000_000_000;
+        timeout.tv_sec += 1;
+    }
+
+    // Create umtx_timeout struct with that absolute timeout.
+    let umtx_timeout = libc::_umtx_time {
+        _timeout: timeout,
+        _flags: libc::UMTX_ABSTIME,
+        _clockid: libc::CLOCK_MONOTONIC as u32,
+    };
+    let umtx_timeout_ptr = &umtx_timeout as *const _;
+    let umtx_timeout_size = ptr::without_provenance_mut(mem::size_of_val(&umtx_timeout));
+
+    let futex: u32 = 123;
+
+    // Wait for 200ms from now, with nobody waking us up early.
+    unsafe {
+        assert_eq!(
+            libc::_umtx_op(
+                ptr::from_ref(&futex).cast_mut().cast(),
+                libc::UMTX_OP_WAIT_UINT_PRIVATE,
+                123,
+                umtx_timeout_size,
+                umtx_timeout_ptr as *mut _,
+            ),
+            -1
+        );
+        assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::ETIMEDOUT);
+    }
+    assert!((200..1000).contains(&start.elapsed().as_millis()));
+}
+
+fn main() {
+    wait_wake();
+    wake_dangling();
+    wait_wrong_val();
+    wait_relative_timeout();
+    wait_absolute_timeout();
+}
diff --git a/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs b/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs
index ce829eee227..2796541a3d7 100644
--- a/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs
+++ b/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs
@@ -9,6 +9,10 @@ use std::thread;
 use windows_sys::Win32::Foundation::{HANDLE, WAIT_OBJECT_0};
 use windows_sys::Win32::System::Threading::{INFINITE, WaitForSingleObject};
 
+#[derive(Copy, Clone)]
+struct UnsafeSendWrapper<T>(T);
+unsafe impl<T> Send for UnsafeSendWrapper<T> {}
+
 fn main() {
     static FLAG: AtomicBool = AtomicBool::new(false);
 
@@ -17,10 +21,12 @@ fn main() {
             thread::yield_now();
         }
     })
-    .into_raw_handle() as HANDLE;
+    .into_raw_handle();
+    let blocker = UnsafeSendWrapper(blocker as HANDLE);
 
     let waiter = move || unsafe {
-        assert_eq!(WaitForSingleObject(blocker, INFINITE), WAIT_OBJECT_0);
+        let blocker = blocker; // circumvent per-field capturing
+        assert_eq!(WaitForSingleObject(blocker.0, INFINITE), WAIT_OBJECT_0);
     };
 
     let waiter1 = thread::spawn(waiter);
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs
index 99d6d2b38f8..116cde4b425 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs
@@ -1,4 +1,5 @@
 //@ignore-target: windows # File handling is not implemented yet
+//@ignore-target: solaris # Does not have flock
 //@compile-flags: -Zmiri-disable-isolation
 
 use std::fs::File;
diff --git a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs
new file mode 100644
index 00000000000..a015464dbde
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs
@@ -0,0 +1,207 @@
+//@only-target: windows # this directly tests windows-only functions
+//@compile-flags: -Zmiri-disable-isolation
+#![allow(nonstandard_style)]
+
+use std::os::windows::ffi::OsStrExt;
+use std::path::Path;
+use std::ptr;
+
+#[path = "../../utils/mod.rs"]
+mod utils;
+
+use windows_sys::Win32::Foundation::{
+    CloseHandle, ERROR_ACCESS_DENIED, ERROR_ALREADY_EXISTS, ERROR_IO_DEVICE, GENERIC_READ,
+    GENERIC_WRITE, GetLastError, RtlNtStatusToDosError, STATUS_ACCESS_DENIED,
+    STATUS_IO_DEVICE_ERROR,
+};
+use windows_sys::Win32::Storage::FileSystem::{
+    BY_HANDLE_FILE_INFORMATION, CREATE_ALWAYS, CREATE_NEW, CreateFileW, FILE_ATTRIBUTE_DIRECTORY,
+    FILE_ATTRIBUTE_NORMAL, FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT,
+    FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, GetFileInformationByHandle, OPEN_ALWAYS,
+    OPEN_EXISTING,
+};
+
+fn main() {
+    unsafe {
+        test_create_dir_file();
+        test_create_normal_file();
+        test_create_always_twice();
+        test_open_always_twice();
+        test_open_dir_reparse();
+        test_ntstatus_to_dos();
+    }
+}
+
+unsafe fn test_create_dir_file() {
+    let temp = utils::tmp();
+    let raw_path = to_wide_cstr(&temp);
+    // Open the `temp` directory.
+    let handle = CreateFileW(
+        raw_path.as_ptr(),
+        GENERIC_READ,
+        FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+        ptr::null_mut(),
+        OPEN_EXISTING,
+        FILE_FLAG_BACKUP_SEMANTICS,
+        ptr::null_mut(),
+    );
+    assert_ne!(handle.addr(), usize::MAX, "CreateFileW Failed: {}", GetLastError());
+    let mut info = std::mem::zeroed::<BY_HANDLE_FILE_INFORMATION>();
+    if GetFileInformationByHandle(handle, &mut info) == 0 {
+        panic!("Failed to get file information")
+    };
+    assert!(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY != 0);
+    if CloseHandle(handle) == 0 {
+        panic!("Failed to close file")
+    };
+}
+
+unsafe fn test_create_normal_file() {
+    let temp = utils::tmp().join("test.txt");
+    let raw_path = to_wide_cstr(&temp);
+    let handle = CreateFileW(
+        raw_path.as_ptr(),
+        GENERIC_READ | GENERIC_WRITE,
+        FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+        ptr::null_mut(),
+        CREATE_NEW,
+        0,
+        ptr::null_mut(),
+    );
+    assert_ne!(handle.addr(), usize::MAX, "CreateFileW Failed: {}", GetLastError());
+    let mut info = std::mem::zeroed::<BY_HANDLE_FILE_INFORMATION>();
+    if GetFileInformationByHandle(handle, &mut info) == 0 {
+        panic!("Failed to get file information: {}", GetLastError())
+    };
+    assert!(info.dwFileAttributes & FILE_ATTRIBUTE_NORMAL != 0);
+    if CloseHandle(handle) == 0 {
+        panic!("Failed to close file")
+    };
+
+    // Test metadata-only handle
+    let handle = CreateFileW(
+        raw_path.as_ptr(),
+        0,
+        FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+        ptr::null_mut(),
+        OPEN_EXISTING,
+        0,
+        ptr::null_mut(),
+    );
+    assert_ne!(handle.addr(), usize::MAX, "CreateFileW Failed: {}", GetLastError());
+    let mut info = std::mem::zeroed::<BY_HANDLE_FILE_INFORMATION>();
+    if GetFileInformationByHandle(handle, &mut info) == 0 {
+        panic!("Failed to get file information: {}", GetLastError())
+    };
+    assert!(info.dwFileAttributes & FILE_ATTRIBUTE_NORMAL != 0);
+    if CloseHandle(handle) == 0 {
+        panic!("Failed to close file")
+    };
+}
+
+/// Tests that CREATE_ALWAYS sets the error value correctly based on whether the file already exists
+unsafe fn test_create_always_twice() {
+    let temp = utils::tmp().join("test_create_always.txt");
+    let raw_path = to_wide_cstr(&temp);
+    let handle = CreateFileW(
+        raw_path.as_ptr(),
+        GENERIC_READ | GENERIC_WRITE,
+        FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+        ptr::null_mut(),
+        CREATE_ALWAYS,
+        0,
+        ptr::null_mut(),
+    );
+    assert_ne!(handle.addr(), usize::MAX, "CreateFileW Failed: {}", GetLastError());
+    assert_eq!(GetLastError(), 0);
+    if CloseHandle(handle) == 0 {
+        panic!("Failed to close file")
+    };
+
+    let handle = CreateFileW(
+        raw_path.as_ptr(),
+        GENERIC_READ | GENERIC_WRITE,
+        FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+        ptr::null_mut(),
+        CREATE_ALWAYS,
+        0,
+        ptr::null_mut(),
+    );
+    assert_ne!(handle.addr(), usize::MAX, "CreateFileW Failed: {}", GetLastError());
+    assert_eq!(GetLastError(), ERROR_ALREADY_EXISTS);
+    if CloseHandle(handle) == 0 {
+        panic!("Failed to close file")
+    };
+}
+
+/// Tests that OPEN_ALWAYS sets the error value correctly based on whether the file already exists
+unsafe fn test_open_always_twice() {
+    let temp = utils::tmp().join("test_open_always.txt");
+    let raw_path = to_wide_cstr(&temp);
+    let handle = CreateFileW(
+        raw_path.as_ptr(),
+        GENERIC_READ | GENERIC_WRITE,
+        FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+        ptr::null_mut(),
+        OPEN_ALWAYS,
+        0,
+        ptr::null_mut(),
+    );
+    assert_ne!(handle.addr(), usize::MAX, "CreateFileW Failed: {}", GetLastError());
+    assert_eq!(GetLastError(), 0);
+    if CloseHandle(handle) == 0 {
+        panic!("Failed to close file")
+    };
+
+    let handle = CreateFileW(
+        raw_path.as_ptr(),
+        GENERIC_READ | GENERIC_WRITE,
+        FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+        ptr::null_mut(),
+        OPEN_ALWAYS,
+        0,
+        ptr::null_mut(),
+    );
+    assert_ne!(handle.addr(), usize::MAX, "CreateFileW Failed: {}", GetLastError());
+    assert_eq!(GetLastError(), ERROR_ALREADY_EXISTS);
+    if CloseHandle(handle) == 0 {
+        panic!("Failed to close file")
+    };
+}
+
+// TODO: Once we support more of the std API, it would be nice to test against an actual symlink
+unsafe fn test_open_dir_reparse() {
+    let temp = utils::tmp();
+    let raw_path = to_wide_cstr(&temp);
+    // Open the `temp` directory.
+    let handle = CreateFileW(
+        raw_path.as_ptr(),
+        GENERIC_READ,
+        FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+        ptr::null_mut(),
+        OPEN_EXISTING,
+        FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
+        ptr::null_mut(),
+    );
+    assert_ne!(handle.addr(), usize::MAX, "CreateFileW Failed: {}", GetLastError());
+    let mut info = std::mem::zeroed::<BY_HANDLE_FILE_INFORMATION>();
+    if GetFileInformationByHandle(handle, &mut info) == 0 {
+        panic!("Failed to get file information")
+    };
+    assert!(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY != 0);
+    if CloseHandle(handle) == 0 {
+        panic!("Failed to close file")
+    };
+}
+
+unsafe fn test_ntstatus_to_dos() {
+    // We won't test all combinations, just a couple common ones
+    assert_eq!(RtlNtStatusToDosError(STATUS_IO_DEVICE_ERROR), ERROR_IO_DEVICE);
+    assert_eq!(RtlNtStatusToDosError(STATUS_ACCESS_DENIED), ERROR_ACCESS_DENIED);
+}
+
+fn to_wide_cstr(path: &Path) -> Vec<u16> {
+    let mut raw_path = path.as_os_str().encode_wide().collect::<Vec<_>>();
+    raw_path.extend([0, 0]);
+    raw_path
+}
diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs
index 05ac5e82b56..cd60b6bd563 100644
--- a/src/tools/miri/tests/pass/float.rs
+++ b/src/tools/miri/tests/pass/float.rs
@@ -38,8 +38,9 @@ macro_rules! assert_approx_eq {
     }};
 
     ($a:expr, $b: expr) => {
-        // accept up to 64ULP (16ULP for host floats and 16ULP for miri artificial error and 32 for any rounding errors)
-        assert_approx_eq!($a, $b, 64);
+        // accept up to 12ULP (4ULP for host floats and 4ULP for miri artificial error and 4 for any additional effects
+        // due to having multiple error sources.
+        assert_approx_eq!($a, $b, 12);
     };
 }
 
diff --git a/src/tools/miri/tests/pass/issues/issue-134713-swap_nonoverlapping_untyped.rs b/src/tools/miri/tests/pass/issues/issue-134713-swap_nonoverlapping_untyped.rs
new file mode 100644
index 00000000000..27ea12398d8
--- /dev/null
+++ b/src/tools/miri/tests/pass/issues/issue-134713-swap_nonoverlapping_untyped.rs
@@ -0,0 +1,30 @@
+use std::mem::{align_of, size_of};
+
+// See <https://github.com/rust-lang/rust/issues/134713>
+
+#[repr(C)]
+struct Foo(usize, u8);
+
+fn main() {
+    let buf1: [usize; 2] = [1000, 2000];
+    let buf2: [usize; 2] = [3000, 4000];
+
+    // Foo and [usize; 2] have the same size and alignment,
+    // so swap_nonoverlapping should treat them the same
+    assert_eq!(size_of::<Foo>(), size_of::<[usize; 2]>());
+    assert_eq!(align_of::<Foo>(), align_of::<[usize; 2]>());
+
+    let mut b1 = buf1;
+    let mut b2 = buf2;
+    // Safety: b1 and b2 are distinct local variables,
+    // with the same size and alignment as Foo.
+    unsafe {
+        std::ptr::swap_nonoverlapping(
+            b1.as_mut_ptr().cast::<Foo>(),
+            b2.as_mut_ptr().cast::<Foo>(),
+            1,
+        );
+    }
+    assert_eq!(b1, buf2);
+    assert_eq!(b2, buf1);
+}
diff --git a/src/tools/miri/tests/pass/path.rs b/src/tools/miri/tests/pass/path.rs
index 299ee6cfe9d..7428d0afcc6 100644
--- a/src/tools/miri/tests/pass/path.rs
+++ b/src/tools/miri/tests/pass/path.rs
@@ -6,7 +6,11 @@ mod utils;
 
 #[track_caller]
 fn assert_absolute_eq(in_: &str, out: &str) {
-    assert_eq!(absolute(in_).unwrap().as_os_str(), Path::new(out).as_os_str());
+    assert_eq!(
+        absolute(in_).unwrap().as_os_str(),
+        Path::new(out).as_os_str(),
+        "incorrect absolute path for {in_:?}"
+    );
 }
 
 fn test_absolute() {
@@ -29,11 +33,28 @@ fn test_absolute() {
         assert_absolute_eq(r"\\?\C:\path\to\file", r"\\?\C:\path\to\file");
         assert_absolute_eq(r"\\?\UNC\server\share\to\file", r"\\?\UNC\server\share\to\file");
         assert_absolute_eq(r"\\?\PIPE\name", r"\\?\PIPE\name");
+        assert_absolute_eq(r"\\server\share\NUL", r"\\server\share\NUL");
+        // This fails on Windows 10 hosts. FIXME: enable this once GHA runners are on Windows 11.
+        //assert_absolute_eq(r"C:\path\to\COM1", r"C:\path\to\COM1");
         // Verbatim paths are always unchanged, no matter what.
         assert_absolute_eq(r"\\?\path.\to/file..", r"\\?\path.\to/file..");
-
+        // Trailing dot is removed here.
         assert_absolute_eq(r"C:\path..\to.\file.", r"C:\path..\to\file");
+        // `..` is resolved here.
+        assert_absolute_eq(r"C:\path\to\..\file", r"C:\path\file");
+        assert_absolute_eq(r"C:\path\to\..\..\file", r"C:\file");
+        assert_absolute_eq(r"C:\path\to\..\..\..\..\..\..\file", r"C:\file");
+        assert_absolute_eq(r"C:\..", r"C:\");
+        assert_absolute_eq(r"\\server\share\to\path\with\..\file", r"\\server\share\to\path\file");
+        assert_absolute_eq(r"\\server\share\to\..\..\..\..\file", r"\\server\share\file");
+        assert_absolute_eq(r"\\server\share\..", r"\\server\share");
+        // Magic filenames.
+        assert_absolute_eq(r"NUL", r"\\.\NUL");
+        assert_absolute_eq(r"nul", r"\\.\nul");
         assert_absolute_eq(r"COM1", r"\\.\COM1");
+        assert_absolute_eq(r"com1", r"\\.\com1");
+        assert_absolute_eq(r"C:\path\to\NUL", r"\\.\NUL");
+        assert_absolute_eq(r"C:\path\to\nul", r"\\.\nul");
     } else {
         panic!("unsupported OS");
     }
diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs
index 289c6aa2fce..6ad23055f30 100644
--- a/src/tools/miri/tests/pass/shims/fs.rs
+++ b/src/tools/miri/tests/pass/shims/fs.rs
@@ -1,4 +1,3 @@
-//@ignore-target: windows # File handling is not implemented yet
 //@compile-flags: -Zmiri-disable-isolation
 
 #![feature(io_error_more)]
@@ -18,20 +17,23 @@ mod utils;
 
 fn main() {
     test_path_conversion();
-    test_file();
-    test_file_clone();
-    test_file_create_new();
-    test_seek();
-    test_metadata();
-    test_file_set_len();
-    test_file_sync();
-    test_errors();
-    test_rename();
-    test_directory();
-    test_canonicalize();
-    test_from_raw_os_error();
-    #[cfg(unix)]
-    test_pread_pwrite();
+    // Windows file handling is very incomplete.
+    if cfg!(not(windows)) {
+        test_file();
+        test_file_create_new();
+        test_seek();
+        test_file_clone();
+        test_metadata();
+        test_file_set_len();
+        test_file_sync();
+        test_errors();
+        test_rename();
+        test_directory();
+        test_canonicalize();
+        test_from_raw_os_error();
+        #[cfg(unix)]
+        test_pread_pwrite();
+    }
 }
 
 fn test_path_conversion() {
@@ -144,10 +146,10 @@ fn test_metadata() {
     let path = utils::prepare_with_content("miri_test_fs_metadata.txt", bytes);
 
     // Test that metadata of an absolute path is correct.
-    check_metadata(bytes, &path).unwrap();
+    check_metadata(bytes, &path).expect("absolute path metadata");
     // Test that metadata of a relative path is correct.
     std::env::set_current_dir(path.parent().unwrap()).unwrap();
-    check_metadata(bytes, Path::new(path.file_name().unwrap())).unwrap();
+    check_metadata(bytes, Path::new(path.file_name().unwrap())).expect("relative path metadata");
 
     // Removing file should succeed.
     remove_file(&path).unwrap();
diff --git a/src/tools/miri/triagebot.toml b/src/tools/miri/triagebot.toml
index 4e013764d87..60e80c3f673 100644
--- a/src/tools/miri/triagebot.toml
+++ b/src/tools/miri/triagebot.toml
@@ -40,3 +40,9 @@ unless = ["S-blocked", "S-waiting-on-team", "S-waiting-on-review"]
 
 # Automatically close and reopen PRs made by bots to run CI on them
 [bot-pull-requests]
+
+# Canonicalize issue numbers to avoid closing the wrong issue when upstreaming this subtree
+[canonicalize-issue-links]
+
+# Prevents mentions in commits to avoid users being spammed
+[no-mentions]
diff --git a/src/tools/opt-dist/src/training.rs b/src/tools/opt-dist/src/training.rs
index 30c79f95947..47159a43140 100644
--- a/src/tools/opt-dist/src/training.rs
+++ b/src/tools/opt-dist/src/training.rs
@@ -70,7 +70,9 @@ fn merge_llvm_profiles(
     profdata: LlvmProfdata,
 ) -> anyhow::Result<()> {
     let llvm_profdata = match profdata {
-        LlvmProfdata::Host => env.host_llvm_dir().join("bin/llvm-profdata"),
+        LlvmProfdata::Host => {
+            env.host_llvm_dir().join(format!("bin/llvm-profdata{}", executable_extension()))
+        }
         LlvmProfdata::Target => env
             .build_artifacts()
             .join("llvm")
diff --git a/src/tools/run-make-support/src/artifact_names.rs b/src/tools/run-make-support/src/artifact_names.rs
index 8968f831542..b0d588d3550 100644
--- a/src/tools/run-make-support/src/artifact_names.rs
+++ b/src/tools/run-make-support/src/artifact_names.rs
@@ -1,11 +1,11 @@
 //! A collection of helpers to construct artifact names, such as names of dynamic or static
-//! librarys which are target-dependent.
-
-// FIXME(jieyouxu): convert these to return `PathBuf`s instead of strings!
+//! libraries which are target-dependent.
 
+use crate::target;
 use crate::targets::is_msvc;
 
 /// Construct the static library name based on the target.
+#[track_caller]
 #[must_use]
 pub fn static_lib_name(name: &str) -> String {
     assert!(!name.contains(char::is_whitespace), "static library name cannot contain whitespace");
@@ -14,15 +14,34 @@ pub fn static_lib_name(name: &str) -> String {
 }
 
 /// Construct the dynamic library name based on the target.
+#[track_caller]
 #[must_use]
 pub fn dynamic_lib_name(name: &str) -> String {
     assert!(!name.contains(char::is_whitespace), "dynamic library name cannot contain whitespace");
 
-    format!("{}{name}.{}", std::env::consts::DLL_PREFIX, std::env::consts::DLL_EXTENSION)
+    format!("{}{name}.{}", dynamic_lib_prefix(), dynamic_lib_extension())
+}
+
+fn dynamic_lib_prefix() -> &'static str {
+    if target().contains("windows") { "" } else { "lib" }
 }
 
-/// Construct the name of the import library for the dynamic library, exclusive to MSVC and
-/// accepted by link.exe.
+/// Construct the dynamic library extension based on the target.
+#[must_use]
+pub fn dynamic_lib_extension() -> &'static str {
+    let target = target();
+
+    if target.contains("apple") {
+        "dylib"
+    } else if target.contains("windows") {
+        "dll"
+    } else {
+        "so"
+    }
+}
+
+/// Construct the name of the import library for the dynamic library, exclusive to MSVC and accepted
+/// by link.exe.
 #[track_caller]
 #[must_use]
 pub fn msvc_import_dynamic_lib_name(name: &str) -> String {
@@ -32,20 +51,28 @@ pub fn msvc_import_dynamic_lib_name(name: &str) -> String {
     format!("{name}.dll.lib")
 }
 
-/// Construct the dynamic library extension based on the target.
-#[must_use]
-pub fn dynamic_lib_extension() -> &'static str {
-    std::env::consts::DLL_EXTENSION
-}
-
 /// Construct the name of a rust library (rlib).
+#[track_caller]
 #[must_use]
 pub fn rust_lib_name(name: &str) -> String {
     format!("lib{name}.rlib")
 }
 
 /// Construct the binary (executable) name based on the target.
+#[track_caller]
 #[must_use]
 pub fn bin_name(name: &str) -> String {
-    format!("{name}{}", std::env::consts::EXE_SUFFIX)
+    let target = target();
+
+    if target.contains("windows") {
+        format!("{name}.exe")
+    } else if target.contains("uefi") {
+        format!("{name}.efi")
+    } else if target.contains("wasm") {
+        format!("{name}.wasm")
+    } else if target.contains("nvptx") {
+        format!("{name}.ptx")
+    } else {
+        name.to_string()
+    }
 }
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index fd22ff6c8bc..c75d500d2f0 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -17,6 +17,7 @@ pub mod assertion_helpers;
 pub mod diff;
 pub mod env;
 pub mod external_deps;
+pub mod linker;
 pub mod path_helpers;
 pub mod run;
 pub mod scoped_run;
diff --git a/src/tools/run-make-support/src/linker.rs b/src/tools/run-make-support/src/linker.rs
new file mode 100644
index 00000000000..89093cf0113
--- /dev/null
+++ b/src/tools/run-make-support/src/linker.rs
@@ -0,0 +1,36 @@
+use regex::Regex;
+
+use crate::{Rustc, is_msvc};
+
+/// Asserts that `rustc` uses LLD for linking when executed.
+pub fn assert_rustc_uses_lld(rustc: &mut Rustc) {
+    let stderr = get_stderr_with_linker_messages(rustc);
+    assert!(
+        has_lld_version_in_logs(&stderr),
+        "LLD version should be present in rustc stderr:\n{stderr}"
+    );
+}
+
+/// Asserts that `rustc` doesn't use LLD for linking when executed.
+pub fn assert_rustc_doesnt_use_lld(rustc: &mut Rustc) {
+    let stderr = get_stderr_with_linker_messages(rustc);
+    assert!(
+        !has_lld_version_in_logs(&stderr),
+        "LLD version should NOT be present in rustc stderr:\n{stderr}"
+    );
+}
+
+fn get_stderr_with_linker_messages(rustc: &mut Rustc) -> String {
+    // lld-link is used if msvc, otherwise a gnu-compatible lld is used.
+    let linker_version_flag = if is_msvc() { "--version" } else { "-Wl,-v" };
+
+    let output = rustc.arg("-Wlinker-messages").link_arg(linker_version_flag).run();
+    output.stderr_utf8()
+}
+
+fn has_lld_version_in_logs(stderr: &str) -> bool {
+    // Strip the `-Wlinker-messages` wrappers prefixing the linker output.
+    let stderr = Regex::new(r"warning: linker std(out|err):").unwrap().replace_all(&stderr, "");
+    let lld_version_re = Regex::new(r"^LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap();
+    stderr.lines().any(|line| lld_version_re.is_match(line.trim()))
+}
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 1e1d68f7782..745a8097c8a 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -1270,6 +1270,7 @@ dependencies = [
  "edition",
  "expect-test",
  "ra-ap-rustc_lexer",
+ "rustc-literal-escaper",
  "stdx",
  "tracing",
 ]
@@ -1744,6 +1745,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
 
 [[package]]
+name = "rustc-literal-escaper"
+version = "0.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0041b6238913c41fe704213a4a9329e2f685a156d1781998128b4149c230ad04"
+
+[[package]]
 name = "rustc-stable-hash"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1978,10 +1985,10 @@ dependencies = [
  "indexmap",
  "itertools",
  "parser",
- "ra-ap-rustc_lexer",
  "rayon",
  "rowan",
  "rustc-hash 2.0.0",
+ "rustc-literal-escaper",
  "rustc_apfloat",
  "smol_str",
  "stdx",
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index ce2d66000e3..e2219139765 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -136,6 +136,7 @@ pulldown-cmark-to-cmark = "10.0.4"
 pulldown-cmark = { version = "0.9.0", default-features = false }
 rayon = "1.8.0"
 rustc-hash = "2.0.0"
+rustc-literal-escaper = "0.0.2"
 semver = "1.0.14"
 serde = { version = "1.0.192" }
 serde_derive = { version = "1.0.192" }
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 6b470d921f7..80a2d4690d4 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -6882,109 +6882,14 @@ pub fn foo() {}
 
 #[test]
 fn hover_feature() {
-    check(
-        r#"#![feature(intrinsics$0)]"#,
-        expect![[r#"
-            *intrinsics*
-            ```
-            intrinsics
-            ```
-            ___
-
-            # `intrinsics`
-
-            The tracking issue for this feature is: None.
-
-            Intrinsics are rarely intended to be stable directly, but are usually
-            exported in some sort of stable manner. Prefer using the stable interfaces to
-            the intrinsic directly when you can.
-
-            ------------------------
-
-
-            ## Intrinsics with fallback logic
-
-            Many intrinsics can be written in pure rust, albeit inefficiently or without supporting
-            some features that only exist on some backends. Backends can simply not implement those
-            intrinsics without causing any code miscompilations or failures to compile.
-            All intrinsic fallback bodies are automatically made cross-crate inlineable (like `#[inline]`)
-            by the codegen backend, but not the MIR inliner.
-
-            ```rust
-            #![feature(intrinsics)]
-            #![allow(internal_features)]
-
-            #[rustc_intrinsic]
-            const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
-            ```
-
-            Since these are just regular functions, it is perfectly ok to create the intrinsic twice:
-
-            ```rust
-            #![feature(intrinsics)]
-            #![allow(internal_features)]
-
-            #[rustc_intrinsic]
-            const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
-
-            mod foo {
-                #[rustc_intrinsic]
-                const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {
-                    panic!("noisy const dealloc")
-                }
-            }
-
-            ```
-
-            The behaviour on backends that override the intrinsic is exactly the same. On other
-            backends, the intrinsic behaviour depends on which implementation is called, just like
-            with any regular function.
-
-            ## Intrinsics lowered to MIR instructions
-
-            Various intrinsics have native MIR operations that they correspond to. Instead of requiring
-            backends to implement both the intrinsic and the MIR operation, the `lower_intrinsics` pass
-            will convert the calls to the MIR operation. Backends do not need to know about these intrinsics
-            at all. These intrinsics only make sense without a body, and can either be declared as a "rust-intrinsic"
-            or as a `#[rustc_intrinsic]`. The body is never used, as calls to the intrinsic do not exist
-            anymore after MIR analyses.
-
-            ## Intrinsics without fallback logic
-
-            These must be implemented by all backends.
-
-            ### `#[rustc_intrinsic]` declarations
-
-            These are written like intrinsics with fallback bodies, but the body is irrelevant.
-            Use `loop {}` for the body or call the intrinsic recursively and add
-            `#[rustc_intrinsic_must_be_overridden]` to the function to ensure that backends don't
-            invoke the body.
-
-            ### Legacy extern ABI based intrinsics
-
-            These are imported as if they were FFI functions, with the special
-            `rust-intrinsic` ABI. For example, if one was in a freestanding
-            context, but wished to be able to `transmute` between types, and
-            perform efficient pointer arithmetic, one would import those functions
-            via a declaration like
-
-            ```rust
-            #![feature(intrinsics)]
-            #![allow(internal_features)]
-            # fn main() {}
-
-            extern "rust-intrinsic" {
-                fn transmute<T, U>(x: T) -> U;
-
-                fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
-            }
-            ```
-
-            As with any other FFI functions, these are by default always `unsafe` to call.
-            You can add `#[rustc_safe_intrinsic]` to the intrinsic to make it safe to call.
-
-        "#]],
-    )
+    let (analysis, position) = fixture::position(r#"#![feature(intrinsics$0)]"#);
+    analysis
+        .hover(
+            &HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG },
+            FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
+        )
+        .unwrap()
+        .unwrap();
 }
 
 #[test]
diff --git a/src/tools/rust-analyzer/crates/parser/Cargo.toml b/src/tools/rust-analyzer/crates/parser/Cargo.toml
index a36a39dbee6..114a66add63 100644
--- a/src/tools/rust-analyzer/crates/parser/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/parser/Cargo.toml
@@ -14,6 +14,7 @@ rust-version.workspace = true
 [dependencies]
 drop_bomb = "0.1.5"
 ra-ap-rustc_lexer.workspace = true
+rustc-literal-escaper.workspace = true
 tracing = { workspace = true, optional = true }
 
 edition.workspace = true
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 c97596d5097..b0bbc2fa5ff 100644
--- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
@@ -10,7 +10,7 @@
 
 use std::ops;
 
-use rustc_lexer::unescape::{EscapeError, Mode};
+use rustc_literal_escaper::{EscapeError, Mode, unescape_byte, unescape_char, unescape_mixed, unescape_unicode};
 
 use crate::{
     Edition,
@@ -282,7 +282,7 @@ impl<'a> Converter<'a> {
                     let text = &self.res.text[self.offset + 1..][..len - 1];
                     let i = text.rfind('\'').unwrap();
                     let text = &text[..i];
-                    if let Err(e) = rustc_lexer::unescape::unescape_char(text) {
+                    if let Err(e) = unescape_char(text) {
                         err = error_to_diagnostic_message(e, Mode::Char);
                     }
                 }
@@ -295,7 +295,7 @@ impl<'a> Converter<'a> {
                     let text = &self.res.text[self.offset + 2..][..len - 2];
                     let i = text.rfind('\'').unwrap();
                     let text = &text[..i];
-                    if let Err(e) = rustc_lexer::unescape::unescape_byte(text) {
+                    if let Err(e) = unescape_byte(text) {
                         err = error_to_diagnostic_message(e, Mode::Byte);
                     }
                 }
@@ -402,14 +402,14 @@ fn unescape_string_error_message(text: &str, mode: Mode) -> &'static str {
     let mut error_message = "";
     match mode {
         Mode::CStr => {
-            rustc_lexer::unescape::unescape_mixed(text, mode, &mut |_, res| {
+            unescape_mixed(text, mode, &mut |_, res| {
                 if let Err(e) = res {
                     error_message = error_to_diagnostic_message(e, mode);
                 }
             });
         }
         Mode::ByteStr | Mode::Str => {
-            rustc_lexer::unescape::unescape_unicode(text, mode, &mut |_, res| {
+            unescape_unicode(text, mode, &mut |_, res| {
                 if let Err(e) = res {
                     error_message = error_to_diagnostic_message(e, mode);
                 }
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
index 59293ee3f96..80f6d85a3d0 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
@@ -11,7 +11,7 @@ use std::{
 
 use intern::Symbol;
 use proc_macro::bridge::{self, server};
-use span::{FileId, Span, FIXUP_ERASED_FILE_AST_ID_MARKER};
+use span::{Span, FIXUP_ERASED_FILE_AST_ID_MARKER};
 use tt::{TextRange, TextSize};
 
 use crate::server_impl::{literal_kind_to_internal, token_stream::TokenStreamBuilder, TopSubtree};
@@ -27,10 +27,6 @@ mod tt {
 
 type TokenStream = crate::server_impl::TokenStream<Span>;
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub struct SourceFile {
-    file_id: FileId,
-}
 pub struct FreeFunctions;
 
 pub struct RaSpanServer {
@@ -46,7 +42,6 @@ pub struct RaSpanServer {
 impl server::Types for RaSpanServer {
     type FreeFunctions = FreeFunctions;
     type TokenStream = TokenStream;
-    type SourceFile = SourceFile;
     type Span = Span;
     type Symbol = Symbol;
 }
@@ -245,25 +240,17 @@ impl server::TokenStream for RaSpanServer {
     }
 }
 
-impl server::SourceFile for RaSpanServer {
-    fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool {
-        file1 == file2
-    }
-    fn path(&mut self, _file: &Self::SourceFile) -> String {
-        // FIXME
-        String::new()
-    }
-    fn is_real(&mut self, _file: &Self::SourceFile) -> bool {
-        true
-    }
-}
-
 impl server::Span for RaSpanServer {
     fn debug(&mut self, span: Self::Span) -> String {
         format!("{:?}", span)
     }
-    fn source_file(&mut self, span: Self::Span) -> Self::SourceFile {
-        SourceFile { file_id: span.anchor.file_id.file_id() }
+    fn file(&mut self, _: Self::Span) -> String {
+        // FIXME
+        String::new()
+    }
+    fn local_file(&mut self, _: Self::Span) -> Option<String> {
+        // FIXME
+        None
     }
     fn save_span(&mut self, _span: Self::Span) -> usize {
         // FIXME, quote is incompatible with third-party tools
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
index 409cf3cc781..4d7c7c46766 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
@@ -24,8 +24,6 @@ type Literal = tt::Literal;
 type Span = tt::TokenId;
 type TokenStream = crate::server_impl::TokenStream<Span>;
 
-#[derive(Clone)]
-pub struct SourceFile;
 pub struct FreeFunctions;
 
 pub struct TokenIdServer {
@@ -37,7 +35,6 @@ pub struct TokenIdServer {
 impl server::Types for TokenIdServer {
     type FreeFunctions = FreeFunctions;
     type TokenStream = TokenStream;
-    type SourceFile = SourceFile;
     type Span = Span;
     type Symbol = Symbol;
 }
@@ -223,24 +220,15 @@ impl server::TokenStream for TokenIdServer {
     }
 }
 
-impl server::SourceFile for TokenIdServer {
-    fn eq(&mut self, _file1: &Self::SourceFile, _file2: &Self::SourceFile) -> bool {
-        true
-    }
-    fn path(&mut self, _file: &Self::SourceFile) -> String {
-        String::new()
-    }
-    fn is_real(&mut self, _file: &Self::SourceFile) -> bool {
-        true
-    }
-}
-
 impl server::Span for TokenIdServer {
     fn debug(&mut self, span: Self::Span) -> String {
         format!("{:?}", span.0)
     }
-    fn source_file(&mut self, _span: Self::Span) -> Self::SourceFile {
-        SourceFile {}
+    fn file(&mut self, _span: Self::Span) -> String {
+        String::new()
+    }
+    fn local_file(&mut self, _span: Self::Span) -> Option<String> {
+        None
     }
     fn save_span(&mut self, _span: Self::Span) -> usize {
         0
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
index 15de88ea656..4bd365be7ca 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
@@ -97,6 +97,7 @@ fn test_fn_like_macro_clone_raw_ident() {
 }
 
 #[test]
+#[cfg(not(bootstrap))]
 fn test_fn_like_fn_like_span_join() {
     assert_expand(
         "fn_like_span_join",
@@ -111,6 +112,7 @@ fn test_fn_like_fn_like_span_join() {
 }
 
 #[test]
+#[cfg(not(bootstrap))]
 fn test_fn_like_fn_like_span_ops() {
     assert_expand(
         "fn_like_span_ops",
diff --git a/src/tools/rust-analyzer/crates/syntax/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/Cargo.toml
index 3fe6e01dc3c..6b356398204 100644
--- a/src/tools/rust-analyzer/crates/syntax/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/syntax/Cargo.toml
@@ -17,13 +17,12 @@ either.workspace = true
 itertools.workspace = true
 rowan = "=0.15.15"
 rustc-hash.workspace = true
+rustc-literal-escaper.workspace = true
 indexmap.workspace = true
 smol_str.workspace = true
 triomphe.workspace = true
 tracing.workspace = true
 
-ra-ap-rustc_lexer.workspace = true
-
 parser.workspace = true
 stdx.workspace = true
 
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 df851ab5b25..08bffb9e3aa 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
@@ -2,7 +2,7 @@
 
 use std::{borrow::Cow, num::ParseIntError};
 
-use rustc_lexer::unescape::{
+use rustc_literal_escaper::{
     unescape_byte, unescape_char, unescape_mixed, unescape_unicode, EscapeError, MixedUnit, Mode,
 };
 use stdx::always;
diff --git a/src/tools/rust-analyzer/crates/syntax/src/lib.rs b/src/tools/rust-analyzer/crates/syntax/src/lib.rs
index c9e9f468dca..21f1ea5f913 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/lib.rs
@@ -19,13 +19,6 @@
 //! [RFC]: <https://github.com/rust-lang/rfcs/pull/2256>
 //! [Swift]: <https://github.com/apple/swift/blob/13d593df6f359d0cb2fc81cfaac273297c539455/lib/Syntax/README.md>
 
-#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
-
-#[cfg(not(feature = "in-rust-tree"))]
-extern crate ra_ap_rustc_lexer as rustc_lexer;
-#[cfg(feature = "in-rust-tree")]
-extern crate rustc_lexer;
-
 mod parsing;
 mod ptr;
 mod syntax_error;
@@ -64,7 +57,7 @@ pub use rowan::{
     api::Preorder, Direction, GreenNode, NodeOrToken, SyntaxText, TextRange, TextSize,
     TokenAtOffset, WalkEvent,
 };
-pub use rustc_lexer::unescape;
+pub use rustc_literal_escaper as unescape;
 pub use smol_str::{format_smolstr, SmolStr, SmolStrBuilder, ToSmolStr};
 
 /// `Parse` is the result of the parsing: a syntax tree and a collection of
diff --git a/src/tools/rust-analyzer/crates/syntax/src/validation.rs b/src/tools/rust-analyzer/crates/syntax/src/validation.rs
index 85eefac734b..71c5f9a946d 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/validation.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/validation.rs
@@ -5,7 +5,7 @@
 mod block;
 
 use rowan::Direction;
-use rustc_lexer::unescape::{self, unescape_mixed, unescape_unicode, Mode};
+use rustc_literal_escaper::{unescape_mixed, unescape_unicode, EscapeError, Mode};
 
 use crate::{
     algo,
@@ -44,8 +44,8 @@ pub(crate) fn validate(root: &SyntaxNode, errors: &mut Vec<SyntaxError>) {
     }
 }
 
-fn rustc_unescape_error_to_string(err: unescape::EscapeError) -> (&'static str, bool) {
-    use unescape::EscapeError as EE;
+fn rustc_unescape_error_to_string(err: EscapeError) -> (&'static str, bool) {
+    use rustc_literal_escaper::EscapeError as EE;
 
     #[rustfmt::skip]
     let err_message = match err {
@@ -127,7 +127,7 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) {
     let text = token.text();
 
     // FIXME: lift this lambda refactor to `fn` (https://github.com/rust-lang/rust-analyzer/pull/2834#discussion_r366199205)
-    let mut push_err = |prefix_len, off, err: unescape::EscapeError| {
+    let mut push_err = |prefix_len, off, err: EscapeError| {
         let off = token.text_range().start() + TextSize::try_from(off + prefix_len).unwrap();
         let (message, is_err) = rustc_unescape_error_to_string(err);
         // FIXME: Emit lexer warnings
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index 08011e1d427..c14372dd6ae 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -156,9 +156,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
 
 [[package]]
 name = "cc"
-version = "1.2.17"
+version = "1.2.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a"
+checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
 dependencies = [
  "shlex",
 ]
@@ -185,9 +185,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.32"
+version = "4.5.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6088f3ae8c3608d19260cd7445411865a485688711b78b5be70d78cd96136f83"
+checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -195,9 +195,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.32"
+version = "4.5.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22a7ef7f676155edfb82daa97f99441f3ebf4a58d5e32f295a56259f1b6facc8"
+checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9"
 dependencies = [
  "anstream",
  "anstyle",
@@ -275,9 +275,9 @@ dependencies = [
 
 [[package]]
 name = "darling"
-version = "0.20.10"
+version = "0.20.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
+checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
 dependencies = [
  "darling_core",
  "darling_macro",
@@ -285,9 +285,9 @@ dependencies = [
 
 [[package]]
 name = "darling_core"
-version = "0.20.10"
+version = "0.20.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
+checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
 dependencies = [
  "fnv",
  "ident_case",
@@ -299,9 +299,9 @@ dependencies = [
 
 [[package]]
 name = "darling_macro"
-version = "0.20.10"
+version = "0.20.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
+checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
 dependencies = [
  "darling_core",
  "quote",
@@ -413,9 +413,9 @@ dependencies = [
 
 [[package]]
 name = "env_logger"
-version = "0.11.7"
+version = "0.11.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3716d7a920fb4fac5d84e9d4bce8ceb321e9414b4409da61b07b75c1e3d0697"
+checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
 dependencies = [
  "anstream",
  "anstyle",
@@ -432,9 +432,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
 
 [[package]]
 name = "errno"
-version = "0.3.10"
+version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
+checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
 dependencies = [
  "libc",
  "windows-sys",
@@ -455,9 +455,9 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
 
 [[package]]
 name = "flate2"
-version = "1.1.0"
+version = "1.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc"
+checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
 dependencies = [
  "crc32fast",
  "miniz_oxide",
@@ -584,14 +584,15 @@ dependencies = [
 
 [[package]]
 name = "iana-time-zone"
-version = "0.1.61"
+version = "0.1.63"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
+checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
 dependencies = [
  "android_system_properties",
  "core-foundation-sys",
  "iana-time-zone-haiku",
  "js-sys",
+ "log",
  "wasm-bindgen",
  "windows-core",
 ]
@@ -646,9 +647,9 @@ dependencies = [
 
 [[package]]
 name = "icu_locid_transform_data"
-version = "1.5.0"
+version = "1.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
+checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d"
 
 [[package]]
 name = "icu_normalizer"
@@ -670,9 +671,9 @@ dependencies = [
 
 [[package]]
 name = "icu_normalizer_data"
-version = "1.5.0"
+version = "1.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
+checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7"
 
 [[package]]
 name = "icu_properties"
@@ -691,9 +692,9 @@ dependencies = [
 
 [[package]]
 name = "icu_properties_data"
-version = "1.5.0"
+version = "1.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
+checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2"
 
 [[package]]
 name = "icu_provider"
@@ -752,9 +753,9 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.8.0"
+version = "2.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
+checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
 dependencies = [
  "equivalent",
  "hashbrown",
@@ -861,9 +862,9 @@ dependencies = [
 
 [[package]]
 name = "log"
-version = "0.4.26"
+version = "0.4.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
+checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
 
 [[package]]
 name = "mac"
@@ -950,6 +951,7 @@ dependencies = [
  "once_cell",
  "pathdiff",
  "pulldown-cmark 0.10.3",
+ "railroad",
  "regex",
  "semver",
  "serde_json",
@@ -980,9 +982,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.8.5"
+version = "0.8.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5"
+checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
 dependencies = [
  "adler2",
 ]
@@ -1028,9 +1030,9 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.21.1"
+version = "1.21.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
 
 [[package]]
 name = "onig"
@@ -1103,9 +1105,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
 
 [[package]]
 name = "pest"
-version = "2.7.15"
+version = "2.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc"
+checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6"
 dependencies = [
  "memchr",
  "thiserror 2.0.12",
@@ -1114,9 +1116,9 @@ dependencies = [
 
 [[package]]
 name = "pest_derive"
-version = "2.7.15"
+version = "2.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e"
+checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5"
 dependencies = [
  "pest",
  "pest_generator",
@@ -1124,9 +1126,9 @@ dependencies = [
 
 [[package]]
 name = "pest_generator"
-version = "2.7.15"
+version = "2.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b"
+checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841"
 dependencies = [
  "pest",
  "pest_meta",
@@ -1137,9 +1139,9 @@ dependencies = [
 
 [[package]]
 name = "pest_meta"
-version = "2.7.15"
+version = "2.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea"
+checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0"
 dependencies = [
  "once_cell",
  "pest",
@@ -1300,6 +1302,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
 
 [[package]]
+name = "railroad"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ecedffc46c1b2cb04f4b80e094eae6b3f3f470a9635f1f396dd5206428f6b58"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
 name = "rand"
 version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1316,9 +1327,9 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
 
 [[package]]
 name = "redox_syscall"
-version = "0.5.10"
+version = "0.5.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1"
+checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3"
 dependencies = [
  "bitflags 2.9.0",
 ]
@@ -1366,9 +1377,9 @@ dependencies = [
 
 [[package]]
 name = "rustix"
-version = "1.0.3"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96"
+checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
 dependencies = [
  "bitflags 2.9.0",
  "errno",
@@ -1476,9 +1487,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
 
 [[package]]
 name = "smallvec"
-version = "1.14.0"
+version = "1.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
+checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
 
 [[package]]
 name = "stable_deref_trait"
@@ -1488,9 +1499,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
 
 [[package]]
 name = "string_cache"
-version = "0.8.8"
+version = "0.8.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "938d512196766101d333398efde81bc1f37b00cb42c2f8350e5df639f040bbbe"
+checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f"
 dependencies = [
  "new_debug_unreachable",
  "parking_lot",
@@ -1879,11 +1890,37 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
 name = "windows-core"
-version = "0.52.0"
+version = "0.61.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
+checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
 dependencies = [
- "windows-targets",
+ "windows-implement",
+ "windows-interface",
+ "windows-link",
+ "windows-result",
+ "windows-strings",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.60.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.59.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
 ]
 
 [[package]]
@@ -1893,6 +1930,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
 
 [[package]]
+name = "windows-result"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
 name = "windows-sys"
 version = "0.59.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/rustc-perf b/src/tools/rustc-perf
-Subproject e22e08623a349b13a3296971a05394d44f76974
+Subproject c0f3b53c8e5de87714d18a5f42998859302ae03
diff --git a/src/tools/rustdoc-gui-test/Cargo.toml b/src/tools/rustdoc-gui-test/Cargo.toml
index f7384a98f85..8d958ac94f3 100644
--- a/src/tools/rustdoc-gui-test/Cargo.toml
+++ b/src/tools/rustdoc-gui-test/Cargo.toml
@@ -5,6 +5,7 @@ edition = "2021"
 
 [dependencies]
 build_helper = { path = "../../build_helper" }
+camino = "1"
 compiletest = { path = "../compiletest" }
 getopts = "0.2"
 walkdir = "2"
diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs
index f1c6e13d3ae..addb0af4a54 100644
--- a/src/tools/rustdoc-gui-test/src/main.rs
+++ b/src/tools/rustdoc-gui-test/src/main.rs
@@ -118,7 +118,11 @@ If you want to install the `browser-ui-test` dependency, run `npm install browse
                     ..Default::default()
                 };
 
-                let test_props = TestProps::from_file(&librs, None, &compiletest_c);
+                let test_props = TestProps::from_file(
+                    &camino::Utf8PathBuf::try_from(librs).unwrap(),
+                    None,
+                    &compiletest_c,
+                );
 
                 if !test_props.compile_flags.is_empty() {
                     cargo.env("RUSTDOCFLAGS", test_props.compile_flags.join(" "));
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index 65120770edd..be6b483bfff 100644
--- a/src/tools/rustfmt/src/expr.rs
+++ b/src/tools/rustfmt/src/expr.rs
@@ -2058,7 +2058,7 @@ fn rewrite_assignment(
     context: &RewriteContext<'_>,
     lhs: &ast::Expr,
     rhs: &ast::Expr,
-    op: Option<&ast::BinOp>,
+    op: Option<&ast::AssignOp>,
     shape: Shape,
 ) -> RewriteResult {
     let operator_str = match op {
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index 322af97d9dc..5c3be769f9e 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -2442,11 +2442,7 @@ pub(crate) fn span_hi_for_param(context: &RewriteContext<'_>, param: &ast::Param
 }
 
 pub(crate) fn is_named_param(param: &ast::Param) -> bool {
-    if let ast::PatKind::Ident(_, ident, _) = param.pat.kind {
-        ident.name != symbol::kw::Empty
-    } else {
-        true
-    }
+    !matches!(param.pat.kind, ast::PatKind::Missing)
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs
index ddf3d2ce96a..1e16aace304 100644
--- a/src/tools/rustfmt/src/macros.rs
+++ b/src/tools/rustfmt/src/macros.rs
@@ -858,18 +858,18 @@ impl MacroArgParser {
         };
 
         self.result.push(ParsedMacroArg {
-            kind: MacroArgKind::Repeat(delim, inner, another, self.last_tok.clone()),
+            kind: MacroArgKind::Repeat(delim, inner, another, self.last_tok),
         });
         Some(())
     }
 
-    fn update_buffer(&mut self, t: &Token) {
+    fn update_buffer(&mut self, t: Token) {
         if self.buf.is_empty() {
-            self.start_tok = t.clone();
+            self.start_tok = t;
         } else {
             let needs_space = match next_space(&self.last_tok.kind) {
-                SpaceState::Ident => ident_like(t),
-                SpaceState::Punctuation => !ident_like(t),
+                SpaceState::Ident => ident_like(&t),
+                SpaceState::Punctuation => !ident_like(&t),
                 SpaceState::Always => true,
                 SpaceState::Never => false,
             };
@@ -878,7 +878,7 @@ impl MacroArgParser {
             }
         }
 
-        self.buf.push_str(&pprust::token_to_string(t));
+        self.buf.push_str(&pprust::token_to_string(&t));
     }
 
     fn need_space_prefix(&self) -> bool {
@@ -937,7 +937,7 @@ impl MacroArgParser {
                 ) if self.is_meta_var => {
                     self.add_meta_variable(&mut iter)?;
                 }
-                TokenTree::Token(ref t, _) => self.update_buffer(t),
+                &TokenTree::Token(t, _) => self.update_buffer(t),
                 &TokenTree::Delimited(_dspan, _spacing, delimited, ref tts) => {
                     if !self.buf.is_empty() {
                         if next_space(&self.last_tok.kind) == SpaceState::Always {
diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs
index 8dc94574503..cb3879f4be8 100644
--- a/src/tools/rustfmt/src/patterns.rs
+++ b/src/tools/rustfmt/src/patterns.rs
@@ -42,6 +42,7 @@ pub(crate) fn is_short_pattern(
 
 fn is_short_pattern_inner(context: &RewriteContext<'_>, pat: &ast::Pat) -> bool {
     match &pat.kind {
+        ast::PatKind::Missing => unreachable!(),
         ast::PatKind::Rest | ast::PatKind::Never | ast::PatKind::Wild | ast::PatKind::Err(_) => {
             true
         }
@@ -100,6 +101,7 @@ impl Rewrite for Pat {
 
     fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
         match self.kind {
+            PatKind::Missing => unreachable!(),
             PatKind::Or(ref pats) => {
                 let pat_strs = pats
                     .iter()
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 8f761d349cc..46e55859a57 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -164,7 +164,6 @@ const EXCEPTIONS_RUSTC_PERF: ExceptionList = &[
     ("brotli-decompressor", "BSD-3-Clause/MIT"),
     ("encoding_rs", "(Apache-2.0 OR MIT) AND BSD-3-Clause"),
     ("inferno", "CDDL-1.0"),
-    ("instant", "BSD-3-Clause"),
     ("ring", NON_STANDARD_LICENSE), // see EXCEPTIONS_NON_STANDARD_LICENSE_DEPS for more.
     ("ryu", "Apache-2.0 OR BSL-1.0"),
     ("snap", "BSD-3-Clause"),
@@ -270,7 +269,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "darling_core",
     "darling_macro",
     "datafrog",
-    "deranged",
     "derive-where",
     "derive_setters",
     "digest",
@@ -311,6 +309,8 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "intl_pluralrules",
     "itertools",
     "itoa",
+    "jiff",
+    "jiff-static",
     "jobserver",
     "lazy_static",
     "leb128",
@@ -328,7 +328,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "miniz_oxide",
     "nix",
     "nu-ansi-term",
-    "num-conv",
     "num_cpus",
     "object",
     "odht",
@@ -341,7 +340,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "pin-project-lite",
     "polonius-engine",
     "portable-atomic", // dependency for platforms doesn't support `AtomicU64` in std
-    "powerfmt",
+    "portable-atomic-util",
     "ppv-lite86",
     "proc-macro-hack",
     "proc-macro2",
@@ -361,7 +360,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "regex-syntax",
     "rustc-demangle",
     "rustc-hash",
-    "rustc-rayon",
+    "rustc-literal-escaper",
     "rustc-rayon-core",
     "rustc-stable-hash",
     "rustc_apfloat",
@@ -394,9 +393,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "thorin-dwp",
     "thread_local",
     "tikv-jemalloc-sys",
-    "time",
-    "time-core",
-    "time-macros",
     "tinystr",
     "tinyvec",
     "tinyvec_macros",
@@ -486,6 +482,7 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[
     "rand_core",
     "rand_xorshift",
     "rustc-demangle",
+    "rustc-literal-escaper",
     "shlex",
     "syn",
     "unicode-ident",
@@ -685,8 +682,10 @@ pub static CRATES: &[&str] = &[
 pub fn has_missing_submodule(root: &Path, submodules: &[&str]) -> bool {
     !CiEnv::is_ci()
         && submodules.iter().any(|submodule| {
+            let path = root.join(submodule);
+            !path.exists()
             // If the directory is empty, we can consider it as an uninitialized submodule.
-            read_dir(root.join(submodule)).unwrap().next().is_none()
+            || read_dir(path).unwrap().next().is_none()
         })
 }
 
diff --git a/src/tools/tidy/src/unit_tests.rs b/src/tools/tidy/src/unit_tests.rs
index 708e4ef8085..90ef36d5882 100644
--- a/src/tools/tidy/src/unit_tests.rs
+++ b/src/tools/tidy/src/unit_tests.rs
@@ -1,11 +1,13 @@
-//! Tidy check to ensure `#[test]` and `#[bench]` are not used directly inside `core`.
+//! Tidy check to ensure `#[test]` and `#[bench]` are not used directly inside
+//! `core` or `alloc`.
 //!
-//! `#![no_core]` libraries cannot be tested directly due to duplicating lang
-//! items. All tests and benchmarks must be written externally in `core/{tests,benches}`.
+//! `core` and `alloc` cannot be tested directly due to duplicating lang items.
+//! All tests and benchmarks must be written externally in
+//! `{coretests,alloctests}/{tests,benches}`.
 //!
-//! Outside of core tests and benchmarks should be outlined into separate files
-//! named `tests.rs` or `benches.rs`, or directories named `tests` or `benches` unconfigured
-//! during normal build.
+//! Outside of `core` and `alloc`, tests and benchmarks should be outlined into
+//! separate files named `tests.rs` or `benches.rs`, or directories named
+//! `tests` or `benches` unconfigured during normal build.
 
 use std::path::Path;
 
@@ -14,40 +16,51 @@ use crate::walk::{filter_dirs, walk};
 pub fn check(root_path: &Path, bad: &mut bool) {
     let core = root_path.join("core");
     let core_copy = core.clone();
-    let core_tests = core.join("tests");
-    let core_benches = core.join("benches");
-    let is_core = move |path: &Path| {
-        path.starts_with(&core)
-            && !(path.starts_with(&core_tests) || path.starts_with(&core_benches))
-    };
+    let is_core = move |path: &Path| path.starts_with(&core);
+    let alloc = root_path.join("alloc");
+    let alloc_copy = alloc.clone();
+    let is_alloc = move |path: &Path| path.starts_with(&alloc);
 
     let skip = move |path: &Path, is_dir| {
         let file_name = path.file_name().unwrap_or_default();
         if is_dir {
             filter_dirs(path)
                 || path.ends_with("src/doc")
-                || (file_name == "tests" || file_name == "benches") && !is_core(path)
+                || (file_name == "tests" || file_name == "benches")
+                    && !is_core(path)
+                    && !is_alloc(path)
         } else {
             let extension = path.extension().unwrap_or_default();
             extension != "rs"
-                || (file_name == "tests.rs" || file_name == "benches.rs") && !is_core(path)
-                // UI tests with different names
-                || path.ends_with("src/thread/local/dynamic_tests.rs")
-                || path.ends_with("src/sync/mpsc/sync_tests.rs")
+                || (file_name == "tests.rs" || file_name == "benches.rs")
+                    && !is_core(path)
+                    && !is_alloc(path)
+                // Tests which use non-public internals and, as such, need to
+                // have the types in the same crate as the tests themselves. See
+                // the comment in alloctests/lib.rs.
+                || path.ends_with("library/alloc/src/collections/btree/borrow/tests.rs")
+                || path.ends_with("library/alloc/src/collections/btree/map/tests.rs")
+                || path.ends_with("library/alloc/src/collections/btree/node/tests.rs")
+                || path.ends_with("library/alloc/src/collections/btree/set/tests.rs")
+                || path.ends_with("library/alloc/src/collections/linked_list/tests.rs")
+                || path.ends_with("library/alloc/src/collections/vec_deque/tests.rs")
+                || path.ends_with("library/alloc/src/raw_vec/tests.rs")
         }
     };
 
     walk(root_path, skip, &mut |entry, contents| {
         let path = entry.path();
         let is_core = path.starts_with(&core_copy);
+        let is_alloc = path.starts_with(&alloc_copy);
         for (i, line) in contents.lines().enumerate() {
             let line = line.trim();
             let is_test = || line.contains("#[test]") && !line.contains("`#[test]");
             let is_bench = || line.contains("#[bench]") && !line.contains("`#[bench]");
             if !line.starts_with("//") && (is_test() || is_bench()) {
                 let explanation = if is_core {
-                    "core unit tests and benchmarks must be placed into \
-                         `core/tests` or `core/benches`"
+                    "`core` unit tests and benchmarks must be placed into `coretests`"
+                } else if is_alloc {
+                    "`alloc` unit tests and benchmarks must be placed into `alloctests`"
                 } else {
                     "unit tests and benchmarks must be placed into \
                          separate files or directories named \
diff --git a/src/tools/unicode-table-generator/src/range_search.rs b/src/tools/unicode-table-generator/src/range_search.rs
index 9a51979a2f0..02f9cf16d4d 100644
--- a/src/tools/unicode-table-generator/src/range_search.rs
+++ b/src/tools/unicode-table-generator/src/range_search.rs
@@ -45,45 +45,78 @@ const fn bitset_search<
     (word & (1 << (needle % 64) as u64)) != 0
 }
 
-fn decode_prefix_sum(short_offset_run_header: u32) -> u32 {
-    short_offset_run_header & ((1 << 21) - 1)
-}
+#[repr(transparent)]
+struct ShortOffsetRunHeader(u32);
+
+impl ShortOffsetRunHeader {
+    const fn new(start_index: usize, prefix_sum: u32) -> Self {
+        assert!(start_index < (1 << 11));
+        assert!(prefix_sum < (1 << 21));
 
-fn decode_length(short_offset_run_header: u32) -> usize {
-    (short_offset_run_header >> 21) as usize
+        Self((start_index as u32) << 21 | prefix_sum)
+    }
+
+    #[inline]
+    const fn start_index(&self) -> usize {
+        (self.0 >> 21) as usize
+    }
+
+    #[inline]
+    const fn prefix_sum(&self) -> u32 {
+        self.0 & ((1 << 21) - 1)
+    }
 }
 
+/// # Safety
+///
+/// - The last element of `short_offset_runs` must be greater than `std::char::MAX`.
+/// - The start indices of all elements in `short_offset_runs` must be less than `OFFSETS`.
 #[inline(always)]
-fn skip_search<const SOR: usize, const OFFSETS: usize>(
-    needle: u32,
-    short_offset_runs: &[u32; SOR],
+unsafe fn skip_search<const SOR: usize, const OFFSETS: usize>(
+    needle: char,
+    short_offset_runs: &[ShortOffsetRunHeader; SOR],
     offsets: &[u8; OFFSETS],
 ) -> bool {
-    // Note that this *cannot* be past the end of the array, as the last
-    // element is greater than std::char::MAX (the largest possible needle).
-    //
-    // So, we cannot have found it (i.e. Ok(idx) + 1 != length) and the correct
-    // location cannot be past it, so Err(idx) != length either.
-    //
-    // This means that we can avoid bounds checking for the accesses below, too.
+    let needle = needle as u32;
+
     let last_idx =
-        match short_offset_runs.binary_search_by_key(&(needle << 11), |header| header << 11) {
+        match short_offset_runs.binary_search_by_key(&(needle << 11), |header| (header.0 << 11)) {
             Ok(idx) => idx + 1,
             Err(idx) => idx,
         };
+    // SAFETY: `last_idx` *cannot* be past the end of the array, as the last
+    // element is greater than `std::char::MAX` (the largest possible needle)
+    // as guaranteed by the caller.
+    //
+    // So, we cannot have found it (i.e. `Ok(idx) => idx + 1 != length`) and the
+    // correct location cannot be past it, so `Err(idx) => idx != length` either.
+    //
+    // This means that we can avoid bounds checking for the accesses below, too.
+    //
+    // We need to use `intrinsics::assume` since the `panic_nounwind` contained
+    // in `hint::assert_unchecked` may not be optimized out.
+    unsafe { crate::intrinsics::assume(last_idx < SOR) };
 
-    let mut offset_idx = decode_length(short_offset_runs[last_idx]);
+    let mut offset_idx = short_offset_runs[last_idx].start_index();
     let length = if let Some(next) = short_offset_runs.get(last_idx + 1) {
-        decode_length(*next) - offset_idx
+        (*next).start_index() - offset_idx
     } else {
         offsets.len() - offset_idx
     };
+
     let prev =
-        last_idx.checked_sub(1).map(|prev| decode_prefix_sum(short_offset_runs[prev])).unwrap_or(0);
+        last_idx.checked_sub(1).map(|prev| short_offset_runs[prev].prefix_sum()).unwrap_or(0);
 
     let total = needle - prev;
     let mut prefix_sum = 0;
     for _ in 0..(length - 1) {
+        // SAFETY: It is guaranteed that `length <= OFFSETS - offset_idx`,
+        // so it follows that `length - 1 + offset_idx < OFFSETS`, therefore
+        // `offset_idx < OFFSETS` is always true in this loop.
+        //
+        // We need to use `intrinsics::assume` since the `panic_nounwind` contained
+        // in `hint::assert_unchecked` may not be optimized out.
+        unsafe { crate::intrinsics::assume(offset_idx < OFFSETS) };
         let offset = offsets[offset_idx];
         prefix_sum += offset as u32;
         if prefix_sum > total {
diff --git a/src/tools/unicode-table-generator/src/skiplist.rs b/src/tools/unicode-table-generator/src/skiplist.rs
index 8ca18ddc91a..34c9802e122 100644
--- a/src/tools/unicode-table-generator/src/skiplist.rs
+++ b/src/tools/unicode-table-generator/src/skiplist.rs
@@ -1,26 +1,23 @@
-use std::fmt::Write as _;
+use std::fmt::{self, Write as _};
 use std::ops::Range;
 
 use crate::fmt_list;
 use crate::raw_emitter::RawEmitter;
 
 /// This will get packed into a single u32 before inserting into the data set.
-#[derive(Debug, PartialEq)]
+#[derive(PartialEq)]
 struct ShortOffsetRunHeader {
-    /// Note, we only allow for 21 bits here.
-    prefix_sum: u32,
-
     /// Note, we actually only allow for 11 bits here. This should be enough --
     /// our largest sets are around ~1400 offsets long.
-    start_idx: u16,
-}
+    start_index: u16,
 
-impl ShortOffsetRunHeader {
-    fn pack(&self) -> u32 {
-        assert!(self.start_idx < (1 << 11));
-        assert!(self.prefix_sum < (1 << 21));
+    /// Note, we only allow for 21 bits here.
+    prefix_sum: u32,
+}
 
-        (self.start_idx as u32) << 21 | self.prefix_sum
+impl fmt::Debug for ShortOffsetRunHeader {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "ShortOffsetRunHeader::new({}, {})", self.start_index, self.prefix_sum)
     }
 }
 
@@ -53,7 +50,7 @@ impl RawEmitter {
                     coded_offsets.push(offset);
                 } else {
                     short_offset_runs.push(ShortOffsetRunHeader {
-                        start_idx: start.try_into().unwrap(),
+                        start_index: start.try_into().unwrap(),
                         prefix_sum,
                     });
                     // This is just needed to maintain indices even/odd
@@ -71,11 +68,12 @@ impl RawEmitter {
             assert!(inserted);
         }
 
+        writeln!(&mut self.file, "use super::ShortOffsetRunHeader;\n").unwrap();
         writeln!(
             &mut self.file,
-            "static SHORT_OFFSET_RUNS: [u32; {}] = [{}];",
+            "static SHORT_OFFSET_RUNS: [ShortOffsetRunHeader; {}] = [{}];",
             short_offset_runs.len(),
-            fmt_list(short_offset_runs.iter().map(|v| v.pack()))
+            fmt_list(short_offset_runs.iter())
         )
         .unwrap();
         self.bytes_used += 4 * short_offset_runs.len();
@@ -104,15 +102,43 @@ impl RawEmitter {
             writeln!(&mut self.file, "    (c as u32) >= {first_code_point:#04x} && lookup_slow(c)")
                 .unwrap();
             writeln!(&mut self.file, "}}").unwrap();
+            writeln!(&mut self.file).unwrap();
+            writeln!(&mut self.file, "#[inline(never)]").unwrap();
             writeln!(&mut self.file, "fn lookup_slow(c: char) -> bool {{").unwrap();
         } else {
             writeln!(&mut self.file, "pub fn lookup(c: char) -> bool {{").unwrap();
         }
-        writeln!(&mut self.file, "    super::skip_search(",).unwrap();
-        writeln!(&mut self.file, "        c as u32,").unwrap();
-        writeln!(&mut self.file, "        &SHORT_OFFSET_RUNS,").unwrap();
-        writeln!(&mut self.file, "        &OFFSETS,").unwrap();
-        writeln!(&mut self.file, "    )").unwrap();
+        writeln!(&mut self.file, "    const {{").unwrap();
+        writeln!(
+            &mut self.file,
+            "        assert!(SHORT_OFFSET_RUNS.last().unwrap().0 > char::MAX as u32);",
+        )
+        .unwrap();
+        writeln!(&mut self.file, "        let mut i = 0;").unwrap();
+        writeln!(&mut self.file, "        while i < SHORT_OFFSET_RUNS.len() {{").unwrap();
+        writeln!(
+            &mut self.file,
+            "            assert!(SHORT_OFFSET_RUNS[i].start_index() < OFFSETS.len());",
+        )
+        .unwrap();
+        writeln!(&mut self.file, "            i += 1;").unwrap();
+        writeln!(&mut self.file, "        }}").unwrap();
+        writeln!(&mut self.file, "    }}").unwrap();
+        writeln!(
+            &mut self.file,
+            "    // SAFETY: We just ensured the last element of `SHORT_OFFSET_RUNS` is greater than `std::char::MAX`",
+        )
+        .unwrap();
+        writeln!(
+            &mut self.file,
+            "    // and the start indices of all elements in `SHORT_OFFSET_RUNS` are smaller than `OFFSETS.len()`.",
+        )
+        .unwrap();
+        writeln!(
+            &mut self.file,
+            "    unsafe {{ super::skip_search(c, &SHORT_OFFSET_RUNS, &OFFSETS) }}"
+        )
+        .unwrap();
         writeln!(&mut self.file, "}}").unwrap();
     }
 }